1

I have a TableViewController which when run, makes an instance of another class and calls json with it eg.

TableViewController;

-(void)viewDidLoad{
JSONClass *jc = [[JSONClass alloc]init];
jc.JSONClassDelegate = (id)self;
[jc view];
}

JSONClass will proceed to retrieve data from the web and once done, will send a delegate method call "JSONClassDataReceived" to tableViewController. Such as,

JSONClass;

-(void)viewDidLoad{

//codes of URL connection goes here...

NSMutableURLRequest *request = [[NSMutableURLRequest new];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];

 [self performSelectorOnMainThread:@selector(fetchedData:)
                           withObject:responseData waitUntilDone:YES];
}

- (void)fetchedData:(NSData *)responseData {

    NSMutableDictionary *data = [NSJSONSerialization
                                     JSONObjectWithData:responseData
                                     options:NSJSONReadingMutableContainers
                                     error:&error];

if (JSONPromotionsLocationsDelegate && [JSONPromotionsLocationsDelegate respondsToSelector:@selector(JSONPromotionsLocationsDataReceived)]) {
            [JSONPromotionsLocationsDelegate JSONPromotionsLocationsDataReceived];
        }
}

TableViewController;

- (void)JSONClassDataReceived{
[tableView reloadTable];
}

After which relevant data is populated.

How do I stop JSONClass when back button is pressed on TableViewController before the delegate method JSONClassDataReceived is called on my tableViewController?

I tried

jc.JSONClassDelegate = nil;
jc = nil;

when back button is pressed, but my app crashes because JSONClass has reached JSONClassDelegate and thus cannot find the method - (void)JSONClassDataReceived due to the fact that tableViewController view no longer exist. I have also tried implement dealloc in JSONClass. None seem to work.

- (void)dealloc{
    self.view = nil;
}

I have having the error EXC_BAD_ACCESS on the lines,

if (JSONPromotionsLocationsDelegate && [JSONPromotionsLocationsDelegate respondsToSelector:@selector(JSONPromotionsLocationsDataReceived)]) {
            [JSONPromotionsLocationsDelegate JSONPromotionsLocationsDataReceived];
        }
Hexark
  • 413
  • 6
  • 22
  • you are setting jc = nil and then try to access jc.JSONClassDelegate. this won't work because you just set jc to nil. try reversing the order of these statements and see what happens. – Patrick Goley Jul 25 '14 at 17:25
  • Hi @PatrickGoley, actually it's the other way round. JSONClassDelegate is trying to find the method "JSONClassDataReceived" but I have already changed my view at that point of time, which is why it will crash. So What im trying to solve is to stop JSONClassDelegate from calling "JSONClassDataReceived" if my view changes. – Hexark Jul 25 '14 at 17:28
  • in your last block of code, you are trying to set the delegate to nil, but this will not happen because you set jc to nil just prior to that and will not be able to access JSONClassDelegate through a nil pointer (jc). Do you see the issue there? – Patrick Goley Jul 25 '14 at 18:07
  • @PatrickGoley oh... I get it, I have changed it to `jc.JSONClassDelegate = nil; jc = nil;` I'll do some through testing and let you know again :) edited: nope still crash. – Hexark Jul 26 '14 at 01:35
  • 1
    Have you defined your `JSONClassDelegate` property as `weak` reference? – dibi Jul 26 '14 at 07:30
  • Is `JSONClass` itself an `UIViewController`? It seems so because you implement there a `viewDidLoad`. In that case why do you want a view controller for a task (network request) that is not UI-related? – Rivera Jul 28 '14 at 09:04
  • I'm pretty new to Xcode and C, and this is the only way i currently know how to work my calls out. Yes, JSONClass is a viewcontroller that just runs the codes without any views. – Hexark Jul 28 '14 at 16:28

4 Answers4

9

I seem to have fixed the crash by simply setting my delegate to weak instead of assign.

crash

@property (nonatomic, assign)id <JSONClassDelegate> JSONClassDelegate;

no crash

@property (nonatomic, weak)id <JSONClassDelegate> JSONClassDelegate;
Community
  • 1
  • 1
Hexark
  • 413
  • 6
  • 22
2

When posting a question about a crash to Stack Overflow, it's helpful to include the crash log or stack trace to empower your peers to help you solve the problem.

The correct way to troubleshoot an EXC_BAD_ACCESS crash is to use the Zombies instrument of Instruments. This will tell you exactly what is causing this problem.

Without that information, we can only guess.

But in your case, I can take an educated guess. Your delegate is being deallocated at some point, and after that you are attempting to use the deallocated memory. This is most likely because you have not declared the delegate as a weak reference. This is specifically mentioned at several points in the documentation.

First, declare your delegate as a weak property.

@property (nonatomic, weak) id JSONClassDelegate;

Don't forget to synthesize it. Not synthesizing properties can lead to bad things.

Now in the methods where you call your delegate you should make it a strong reference for the duration of the method. This prevents it from being deallocated while you are using it. For example:

__strong id aDelegate = [self JSONClassDelegate];
if ([JSONClassDelegate respondsToSelector:@selector(JSONPromotionsLocationsDataReceived)]) {
    [JSONClassDelegate JSONPromotionsLocationsDataReceived];
}

This creates a strong local stack variable that points to your weak reference. It will be retained until it goes out of scope.

quellish
  • 21,123
  • 4
  • 76
  • 83
  • 1
    I was using `@property(nonatomic, assign) id JSONPromotionsDelegate;` and have changed it to `weak` instead of `assign`. I have also added the lines `__strong id JSONPromotionsDelegate = [self JSONPromotionsDelegate]; ` It seems to have solved the crash for now! Just having warnings `Local declaration hides instance variable`. Does this also mean I should change all my delegates to weak and make every delegate a strong reference? I have a few other JSONClasses which works the same way. – Hexark Jul 26 '14 at 09:16
  • 1
    It means that a local variable (__strong id JSONPromotionsDelegate) has the same name as an instance variable (property JSONPromotionsDelegate). Change the name of the local variable and you're good to go. Yes, you should update all of your delegates to work this way, and you should check the rest of the app regularly with the Zombies and leaks instruments - it will teach you a lot. – quellish Jul 26 '14 at 17:42
1

First, make sure that before calling your delegate, you do this:

if (self.delegate && [self.delegate respondsToSelector:@selector(JSONClassDataReceived)]) {
    [self.delegate JSONClassDataReceived];
}

Other than that, in your JSONClass' - (void)dealloc method, you can stop the web call. If you're using ARC, make sure you don't call [super dealloc]. For the dealloc method to be called, you'll need to keep nulling out your jc object.

Hope this helps.

Simon Germain
  • 6,834
  • 1
  • 27
  • 42
  • this doesn't work and still caused crashes. giving an EXC_BAD_ACCESS – Hexark Jul 25 '14 at 14:28
  • For whatever class that calls your `JSONClassDataReceived` method. The one that makes the web call. – Simon Germain Jul 25 '14 at 15:57
  • My ClassA makes the call to JSONClass to retrieve data. ClassA does not have a dealloc method. Instead it has a -(IBAction)btnBack:(id)sender{ jc = nil; jc.JSONClassDelegate = nil; } – Hexark Jul 25 '14 at 16:10
  • Wait, your instance of `JSONClass` (`jc` in your original post) has an IBAction in it? This makes no sense. `JSONClass` should have a `dealloc` method that cancels the web call, I'm assuming you're using either `NSURLConnection` or `NSURLSession`. – Simon Germain Jul 25 '14 at 16:51
  • No. my IBAction is in ClassA. IBAction is for back button which will trigger my jc = nil. How do i cancel the webcall. What do I input into dealloc? – Hexark Jul 25 '14 at 17:09
  • If you are using an NSURLConnection object or an NSURLSession object, you need to set that to nil, in your JSONClass class. – Simon Germain Jul 25 '14 at 20:12
  • How would that help? It's not NSURLConnection causing the crash, its the line `if (JSONClassDelegate && [JSONClassDelegate respondsToSelector:@selector(JSONClassDataReceived)]) { [JSONClassDelegate JSONClassDataReceived]; }` causing EXC_BAD_ACCESS – Hexark Jul 26 '14 at 01:34
  • In what method do you call `JSONClassDataReceived`? – Simon Germain Jul 26 '14 at 01:48
  • JSONClassDataReceived is a delegate which is called from [JSONClassDelegate JSONClassDataReceived] which will trigger a call in ClassA. It works the same way as a LocationManager delegate. – Hexark Jul 26 '14 at 02:27
  • You're not answering the question. What method is it called in? – Simon Germain Jul 26 '14 at 02:51
  • After my NSURLConnection I parse JSON, and after the parsing and storage of my data into arrays is completed. All these is happening in JSONClass. This what you're asking? – Hexark Jul 26 '14 at 03:03
  • No, this is not what I'm asking. How are you using NSURLConnection? Delegate? Synchronous call? Async call with a completion block? – Simon Germain Jul 26 '14 at 03:23
1

No, you can't (usefully) "test if an address contains a valid object". Even if you were able to grub around inside the internals of the memory allocation system and determine that your address points to a valid object, that would not necessarily mean that it was the same object that you were previously referring to: the object could have been deallocated and another object created at the same memory address.

Found from here.

Community
  • 1
  • 1
Nirav Gadhiya
  • 6,342
  • 2
  • 37
  • 76