Question

Sorry for bad explanation of my problem. Here are my code and steps updated. I also updated title.
!!!EDIT!!!

1) I am implementing search in ARC project with CoreData database.
2) Search viewController is instantiated from mainStoryboard like this:

Search Controller is in storyboard with identifier "search"

SearchTableViewController *searchController = (SearchTableViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:@"Search"];
[[[self tabBarController] parentViewController] presentViewController:searchController animated:NO completion:nil];

3) The presented view controller with search is closed on event controllerDidEndSearch (for example by clicking on cancel button in UISearchBar).

-(void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
    [self dismissViewControllerAnimated:NO completion:nil];
}

My error happens only when I open and close view controller with search.

4) There is a singleton object that is listening on refresh event.

RefreshService.m

+(RefreshService *)getDefaultRefreshService {
    if (DefaultRefreshService == nil) DefaultRefreshService = [[self allocWithZone:nil] init];
    return DefaultRefreshService;
}
-(id)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:NSSelectorFromString(@"refresh:") name:@"refresh_event" object:nil];
    }
    return self;
}  

5) There is a refresh button that triggers refresh by posting notification

-(IBAction)refreshAction:(id)sender {
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"refresh_event" object:@"OK"]];
}

good case scenarion:
1. Start app.
2. click refresh button
3. Everything works ok, refreshService receives notification and triggers refresh method - defined in point 4)

and bad use case that fails:
1. Start app.
2. click search button - see point 2)
3. click cancel - see point 3)
4. click refresh button - see point 5)
5. and now it fails right before refreshService gets the notification, instead i get errors:

-[NSAutoresizingMaskLayoutConstraint refresh:]: unrecognized selector sent to instance

or

-[__NSCFDictionary refresh:]: unrecognized selector sent to instance

or it fails with SIGABART on main function.

For me it looks like something was bad released, but I am using ARC, so i do not handle releasing objects manualy...

Was it helpful?

Solution

After trying the various options I came to the conclusion that using singleton as observer on NSNotificationCenter event is not thread safe. After moving observer logic from singleton to normal controller everything works just fine. I have tried various implementations of singleton that should be thread safe with ARC but none of them worked as an observer.

Tested singleton implementations:

1) My implementation of singleton

+(RefreshService *)getDefaultRefreshService {
    if (DefaultRefreshService == nil) DefaultRefreshService = [[self allocWithZone:nil] init];
    return DefaultRefreshService;
}

2) implementation from here How do I implement an Objective-C singleton that is compatible with ARC?

+ (RefreshService *)getDefaultRefreshService
{
    static RefreshService *DefaultRefreshService = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        DefaultRefreshService = [[self alloc] init];
    });

    return DefaultRefreshService;
}

3) and implementation from here: What should my Objective-C singleton look like?

+ (void)initialize
{
    static BOOL initialized = NO;
    if(!initialized)
    {
        initialized = YES;
        DefaultRefreshService = [[RefreshService alloc] init];
    }
}

For every three options I have used this init() method:

-(id)init {
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:NSSelectorFromString(@"refresh:") name:@"refresh_event" object:nil];
    }
    return self;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top