简体   繁体   中英

How to save data out of an iOS completion block

I'm basically implementing a fancier NSURLConnection class that downloads data from a server parses it into a dictionary, and returns an NSDictionary of the data. I'm trying add a completion block option (in addition to a delegate option), but it crashes anytime I try to store that data in another class.

        [dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {        
            contentDictionary_ = data;            
    }];

I can NSLog that data just fine, and basically do whatever I want with it, but as soon as I try to save it into another variable it crashes with a really obscure message.

EDIT: the crash message is EXC_BAD_ACCESS, but the stack trace is 0x00000000 error: address doesn't contain a section that points to a section in a object file.

I'm calling this function in the init method of a singleton. It DOES let me save the data if I set this in the completion block.

[SingletonClass sharedInstance].contentDictionary = data

But then the app gets stuck forever because sharedInstance hasn't returned yet, so the singleton object is still nil, so sharedInstance in the completion block calls init again, over and over.

EDIT 2: The singleton code looks like this:

+ (SingletonClass*)sharedInstance {
   static SingletonClass *instance;
   if (!instance) {
       instance = [[SingletonClass alloc] init];
   }
   return instance;
}


- (id)init {
    self = [super init];
    if (self) {
        dataFetcher_ = [[DataFetcher alloc] init];
        NSString *testURL = @"..."  
        [dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {        
            [SingletonClass sharedInstance].contentDictionary = data;

        }];

    }
    return self;
}

Like I said, this works fine but repeats the initialize code over and over until the app crashes. This only happens the first time I run the app on a device, because I cache the data returned and it doesn't crash once I have the data cached. I would like to be able to just say self.contentDictionary = data, but that crashes.

Specify a variable to be used in the block with the __block directive outside of the block:

__block NSDictionary *contentDictionary_;

[dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {        
    contentDictionary_ = data;            
}];

You're invoking recursion before ever setting the "instance". (which I now see you understand from OP).

In your block, you can use the ivar or an accessor instead of

[SingletonClass sharedInstance].contentDictionary

use: _contentDictionary = [data copy]; or self.contentDictionary=data; assuming that the ivar backing the contentDictionary property is _contentDictionary.

It sounds like you tried self.contentDictionary and it failed? I got it to work in a test, with ARC turned, so there may be something about your dataFetcher that is affecting this. In my test dataFetcher just returns a dictionary with a single element.

Turns out the issue was with a bunch of different parts. My URL was empty sometimes, and my data fetcher would just fail immediately and call the completion block. In my completion block I hadn't included any error handling, so if the singleton class hadn't initialized, it would repeat forever. With a real URL this doesn't happen.

I still would like to figure out why it crashes when I try to assign the data to an ivar, though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM