1
votes

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];
        }
4
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
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
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
@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
Have you defined your JSONClassDelegate property as weak reference? - dibi

4 Answers

9
votes

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;
2
votes

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.

1
votes

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.

1
votes

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.