0

by this class I send http requests :

     @interface AsyncRequest()
        @property(strong,nonatomic)NSURLRequest* murlRequest;
        @property(copy) OnCompleted onCompletedBlock;
        @end
        @implementation AsyncRequest
        //Async Request object initialization
        -(instancetype)initWithUrl:(NSString*)urlRequest onCompletedBlock:(OnCompleted) onCompeletedBlock
        {
            self = [super init];
            if(self)
            {
                //blocks


                NSURL* url  = [NSURL URLWithString:[NSStringstringWithFormat:@"%@%@",SERVER_URL,urlRequest]];

                self.onCompletedBlock = onCompeletedBlock;
                self.murlRequest = [NSURLRequest requestWithURL:url];
            }
            return self;
        }
    //call this function to execute the specified request
    -(void)ExecuteRequest
    {
        AsyncRequest * __weak weakself = self;

       //localVariable is used by value, a strong reference is made to localVariable in the block
        NSURLRequest *urlRequest = self.murlRequest;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^(void){
            NSURLResponse *response = nil;
            NSError *error = nil;
            NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
                    //main ui
                    dispatch_async(dispatch_get_main_queue(),^{
                                weakself.onCompletedBlock(data);
                    });
    }
        @end

so I declare onComplete block and and initialize them at initWithUrlFunction then I use weakself to run It.

but the problem I get this error at weakself.onCompletedBlock(data) ->

Thread1:EXC_BAD_ACCESS(code=2,address=0xc)

what's the problem ?

6
  • 2
    You know that there is a sendAsynchronousRequest:queue:completionHandler: method, right? Commented Aug 26, 2014 at 10:58
  • yes I know that, but I want to know what's the problem with my code ? and I think gcd is very light weight !so i prefer using gcd rather than using operations Commented Aug 26, 2014 at 11:01
  • @david show some code about how are you calling this class? The problem lies there? Commented Aug 26, 2014 at 11:11
  • @AsifMujteba ok one minute Commented Aug 26, 2014 at 11:12
  • assign weakself.onCompletedBlock to a strong var first and test it is not nil Commented Aug 26, 2014 at 11:25

2 Answers 2

3

You need to assign weakself.onCompletedBlock to a strong var first and test it is not nil before invoke it.


You need to test block is not nil before call it unless you can guarantee it cannot be nil. Or your app crashes with poor error message like you had. Unlike invoke method on nil object is perfectly safe, invoke a nil block will lead to dereference invalid memory address.

block() will be compiled to something like block->someFunction(block->someStruct) and if block is NULL/0, you get C++ style crash.


You don't want to access a __weak variable multiple times. You have to assign it to a __strong variable then access it. Otherwise it may be released unexpectedly because it is not retained.

__weak Foo *obj = // something
[obj dowork];   // obj may be valid value at this point
[obj dootherwork]; // obj may be nil here even previous call success
id foo = obj->somevar;  // may crash with dereference invalid memory address

what you need to do is

__weak Foo *obj = // something
Foo *strongObj = obj;
if (strongObj) { // not always required
    // you know strongObj is retained and will not be released until it go out of scope
    // so you can access strongObj safely without surprise 
}
Sign up to request clarification or add additional context in comments.

Comments

0

The weakSelf pattern is not appropriate here. It's used to avoid strong reference cycles, which is not a risk here. In this situation, you just want this dispatch_async block retain their constituent objects until the asynchronous blocks execute, so just use self.

By the way, if it's possible that this method might ever be called without supplying a completion block, you should ensure it's not nil, thus:

dispatch_async(dispatch_get_main_queue(),^{
    if (self.onCompletedBlock) {
        self.onCompletedBlock(data);
    }
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.