2012-06-29 19 views
0

這很奇怪。每當我啓用LLVM編譯器優化(-O/-O1或更高版本)時,當我的類的屬性被訪問時,我得到一個EXC_BAD_ACCESS錯誤。該屬性在代碼流中較早訪問,沒有任何問題,但是在「某點」(我知道,這是模糊的)應用程序崩潰。編譯器優化導致類屬性爲EXC_BAD_ACCESS

我看了幾個其他堆棧溢出問題重新:嚴格的別名,但沒有看到(或理解)我可能在我的代碼中打破的地方。這裏的違規類:(靠近類的末端崩潰)

#import "MessageManager.h" 
#import "NSURL+Additions.h" 
#import "NSString+Guid.h" 

static MessageManager *_instance = NULL; 

@interface MessageManager() 

@property (nonatomic, strong) NSMutableDictionary *listeners; 
@property (nonatomic, strong) NSMutableDictionary *senders; 

@end 

@implementation MessageManager 

@synthesize listeners, senders; 

+ (MessageManager *) getInstance 
{ 
    @synchronized(self) 
    { 
     if (self == [MessageManager class] && _instance == NULL) { 
      _instance = [[self alloc] init]; 
      _instance.listeners = [NSMutableDictionary dictionary]; 
      _instance.senders = [NSMutableDictionary dictionary]; 
     } 
    } 
    return (_instance); 
} 

#pragma mark 
#pragma mark Senders 

- (void) addMessage:(Message *)message sender:(void (^)())sender callback:(void (^) (Message *))callback 
{ 
    [self addMessage:message sender:sender callback:callback sendImmediately:NO]; 
} 

- (void) addMessage:(Message *)message sender:(void (^)())sender callback:(void (^) (Message *))callback sendImmediately:(BOOL)sendNow 
{ 
    message.id = [NSString stringWithGuid]; 
    [senders setObject:[NSDictionary dictionaryWithObjectsAndKeys:message, @"message", [sender copy], @"sender", nil] forKey:message.id]; 

    // note: callbacks use the message id and not the key, so that they remain tied to the message and not other keyed events 
    if (callback) [self registerListener:callback forKey:message.id]; 

    if (sendNow) { 
     message.isSent = YES; 
     sender(); 
    } 
} 

- (void) sendAll 
{ 
    [self sendAllForTags:nil]; 
} 

- (void) sendAllForTags:(NSArray *)tags 
{ 
    typedef void (^SenderBlock)(); 
    [senders enumerateKeysAndObjectsUsingBlock:^(NSString *messageId, id wrapper, BOOL *stop) { 

     Message *message = (Message *)[(NSDictionary *)wrapper objectForKey:@"message"]; 
     id sender = [(NSDictionary *)wrapper objectForKey:@"sender"]; 
     BOOL validTag; 
     if (tags && tags.count) { 
      if (message.tags.count) { 
       validTag = false; 
       for (NSString *tag in tags) { 
        if ([message.tags containsObject:tag]) { 
         validTag = true; // found match! ok to send. 
         break; 
        } 
       } 
      } else validTag = false; // tags specified, but none in message, never send 
     } else validTag = true; // no tags specified, always send 

     if ((!message.isSent || message.isRepeatable) && validTag) { 
      message.isSent = YES; 
      ((SenderBlock)sender)(); // send message! 
     } 
    }]; 
} 

#pragma mark 
#pragma mark Listeners 

- (void) registerListener:(void (^) (Message *))listener forKey:(NSString *)key 
{ 
    if (![listeners objectForKey:key]) { 
     [listeners setObject:[NSMutableArray array] forKey:key]; 
    } 
    [(NSMutableArray *)[listeners objectForKey:key] addObject:listener]; 
} 

- (BOOL) handleOpenURL:(NSURL *)url 
{ 
    Message *message = [[Message alloc] initWithJson:[[url queryParams] objectForKey:@"message"]]; 
    NSLog(@"%@", listeners); // <<<<----- CRASH HAPPENS HERE (or the first place in this method that "listeners" is referenced) 
    NSMutableArray *keyedListeners = (NSMutableArray *)[listeners objectForKey:message.key]; 
    typedef void (^ListenerBlock)(Message *); 
    for (ListenerBlock keyedListener in keyedListeners) { 
     keyedListener(message); 
    } 
    return YES; 
} 


@end 

注:registerListener:forKey:被稱爲前幾次handleOpenUrl:被調用,沒有任何錯誤,即使它引用的「聽衆」屬性。

對於上下文,這是我創建的允許發送和接收消息和事件的消息框架的一部分。

編輯:堆棧跟蹤

0 MyApp 0x00026206 testflight_backtrace + 158 
1 MyApp 0x00026e30 TFSignalHandler + 244 
2 libsystem_c.dylib 0x36fc67ec _sigtramp + 48 
3 MyApp 0x00024f7c -[MessageManager handleOpenURL:] (MessageManager.m:112) 
4 MyApp 0x0001c29a -[WebViewController webView:shouldStartLoadWithRequest:navigationType:] (WebViewController.m:327) 
5 UIKit 0x32492482 -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 182 
6 CoreFoundation 0x352cf7e3 __invoking___ + 67 
7 CoreFoundation 0x3522a7b0 -[NSInvocation invoke] + 160 
8 CoreFoundation 0x3522a3ce -[NSInvocation invokeWithTarget:] + 50 
9 WebKit 0x338b1e0c -[_WebSafeForwarder forwardInvocation:] + 252 
10 CoreFoundation 0x352cea82 ___forwarding___ + 666 
11 CoreFoundation 0x3522964f _CF_forwarding_prep_0 + 47 
12 CoreFoundation 0x352cf7e3 __invoking___ + 67 
13 CoreFoundation 0x3522a7b0 -[NSInvocation invoke] + 160 
14 WebCore 0x37060648 _ZL11SendMessageP12NSInvocation + 24 
15 WebCore 0x37073b44 _ZL20HandleDelegateSourcePv + 80 
16 CoreFoundation 0x352a0ad2 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 14 
17 CoreFoundation 0x352a029e __CFRunLoopDoSources0 + 214 
18 CoreFoundation 0x3529f044 __CFRunLoopRun + 652 
19 CoreFoundation 0x352224a4 CFRunLoopRunSpecific + 300 
20 CoreFoundation 0x3522236c CFRunLoopRunInMode + 104 
21 GraphicsServices 0x3651e438 GSEventRunModal + 136 
22 UIKit 0x32318e7c UIApplicationMain + 1080 
23 MyApp 0x0001aa32 main (main.m:34) 
24 MyApp 0x0001a9e7 start + 39 
+0

請提供一個堆棧跟蹤一個a very good write up。 – trojanfoe

回答

1

我認爲這是你沒有正確地複製到集合(聽衆)的塊。看看這個問題:Keep blocks inside a dictionary

有你爲什麼需要這樣做

+0

你是對的!幸運的是,它只需要一個簡單的副本:'[(NSMutableArray *)[li​​steners objectForKey:key] addObject:[listener copy]];'謝謝! –