strong reference to delegates - ios

I read somewhere that if i have delegates in my app, i should keep a weak reference to them
however, when i debug the app, the app doesnt want to move on, when i call on a delegate
because my delegate has already been deallocated by the time it reached that method
why ?
If i put the reference to be "strong" everything works just fine, though i am not sure what are the consequences of that on my memory allocations and the fact that those delegates are not in "sharedInstance" classes....
code:
#interface LoginProcessListener()
#property (nonatomic,weak)id<UserSettingsDelegate>userSettings;
#property (nonatomic,weak)id<DisclaimerDelegate>disclaimerDelegate;
#end
#implementation LoginProcessListener
-(instancetype)initWithUserSettings:(id<UserSettingsDelegate>)userSettings andDisclaimerDelegate:(id<DisclaimerDelegate>)disclaimerDelegate{
self = [super init];
if (self){
[self setUserSettings:userSettings];
[self setDisclaimerDelegate:disclaimerDelegate];
}
return self;
}
-(void)onLoginAuthenticationProcessFinished{
User *user = [_userSettings getUserDetails];
if(user && [_disclaimerDelegate isConfirmedDisclaimer:[user disclaimerInfo]]){
[_disclaimerDelegate confirmedDisclaimer];
}else {
[_disclaimerDelegate needDisplayDisclaimer];
}
}
-(void)onLoggedInUserDetailsReceived:(User *)user{
[_userSettings saveUserDetails:user]; <== here my _userSettings is already nil;
}

when i debug the app, the app doesnt want to move on, when i call on a delegate because my delegate has already been deallocated by the time it reached that method
But that is your bug, which you must track down. The whole point of a delegate is that you must not permit it to die before the thing whose delegate it is. In general, if a delegate dies before the other thing does, you are doing something wrong; it is the job of a delegate to live as long as it is needed.
On the other hand (there is always an "other hand") it may be that what you are calling a delegate is not really a delegate. It is a delegate more or less if it is an object with a primary existence of its own. If it's just a packet of values or a purely ancillary object whose only purpose is in connection with the object keeping a reference to it, then it is not a delegate and a strong reference is correct.

Yours architecture is wrong. It's should be:
#interface UserSettings
#property (nonatomic,weak)id<UserSettingsDelegate>userSettingsDelegate;
#end
#interface Disclaimer
#property (nonatomic,weak)id<DisclaimerDelegate>disclaimerDelegate;
#end
Actually yours userSettings not real delegate, it just member of LoginProcessListener, so you may use strong references.
Commonly id<UserSettingsDelegate> creates UserSettings and own reference on it. If UserSettings will own reference at id<UserSettingsDelegate, then there will be retain loop.

when i debug the app, the app doesnt want to move on, when i call on a
delegate because my delegate has already been deallocated by the time
it reached that method
What's your seeking is how a weakly defined property behaves.
Via the docs: https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html#/apple_ref/doc/uid/TP40011210-CH5-SW30)
Because a weak reference doesn’t keep an object alive, it’s possible for the referenced
object to be deallocated while the reference is still in use. To avoid a dangerous
dangling pointer to the memory originally occupied by the now deallocated object, a weak
reference is automatically set to nil when its object is deallocated.
Simply put, if the delegate is no longer allocated, it's being released elsewhere.
With that said, your bug is likely not there at all, but elsewhere. You're going to have to backtrace _userSession to verify where it's being created and what objects have strong references to it.

Using a strong reference to a delegate is permissible, but you need to understand what is going on as it has risks that you should be aware of.
Apple's documentation kind of glosses over this, just saying that delegate users keep a weak link to the delegate, and in general this is true, but there are cases, and yours may be one of them, where it makes sense to keep a strong reference. In general, this happens in asynchronous code where the delegate might otherwise be released before it is used.
Too much hand waving: here is a concrete example. NSURLConnection needs a delegate to do asynchronous IO. In order to make this reliable and to greatly simplify it's usage, NSURLConnection keeps a strong reference to it's delegate as long as it needs one. Here is a quote from the NSURLConnection documentation :-
"Note: During a request, the connection maintains a strong reference to its delegate. It releases that strong reference when the connection finishes loading, fails, or is canceled"
In simple terms, under ARC, "releases that strong reference" probably means setting the property to nil.
Summary: If you know what you're doing, use strong references when you have to, and document well so that the next person to see that code understands why you did it.

You can temoprarily make a strong reference to the delegate object, which is excatly what NSURLConnectionDelegate protocol does. I do it like this:
Let's say i have a protocol for downloading images.
#implementation AsyncImageLoadManager <NSURLConnectionDelegate>
static char delegateStrongReferenceKey;
.......
-(void)startDownload {
....
objc_setAssociatedObject(self, &delegateStrongRefernceKey, _delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
_imageConnection = [NSURLConnection connectionWithRequest:request delegate:self];
objc_setAssociatedObject(self, &delegateStrongRefernceKey, _delegate, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
_downloadTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ //I use tihs instead of [connection start]; so that download continues if app goes to background
[_imageConnection cancel];
[[UIApplication sharedApplication] endBackgroundTask:_downloadTaskID];
_downloadTaskID = UIBackgroundTaskInvalid;
objc_setAssociatedObject(self, &delegateStrongRefernceKey, nil, OBJC_ASSOCIATION_ASSIGN);
}];
}
..../// and in connectionDidFinishLoading and connectionDidFailWithError you release the strong reference with:
[[UIApplication sharedApplication] endBackgroundTask:_downloadTaskID];
_downloadTaskID = UIBackgroundTaskInvalid;
objc_setAssociatedObject(self, &delegateStrongRefernceKey, nil, OBJC_ASSOCIATION_ASSIGN);

Related

How to prevent EXC_BAD_ACCESS on an object I don't know is released in iOS 9?

I use an NSURLConnection to download a file and when the user taps back I don't necessarily know if the connection is finished and has been properly disposed. So I added the following check where if the connection is not null, cancel it.
if (self.urlConnection){
[self.urlConnection cancel];
}
This worked in iOS 7/8 and I never once received an exception. But now in iOS 9 when I do the check to see if the connection exists (and it doesn't) I get an exception. This is the first line above, before I have actually made a call to the url.
I don't understand why checking to see if an object is nil would ever throw an exception and if it does - how can I be expected to guard against this exception.
Is there a new way to make sure an object exists and hasn't been released before I make a call to it?
Edit: This is how the property is declared:
#property (nonatomic, assign) NSURLConnection *urlConnection;
If the object hasn't actually been instantiated yet, the check works fine. It's only when the connection finishes and becomes nil and then I try to check if it is nil that the check explodes. This wasn't happening on earlier iOS versions.
Yes, there is ... use a weak reference.
__weak typeof(self) weakSelf = self;
...
..
.
[weakSelf.urlConnection cancel]
NSURLConnection is an object and needs to be a strong reference. Assign is only appropriate for primitive values. If you really intended to make this property weak, then use this pattern to ensure that your object does not go out of scope while using it:
//code that goes in some method
NSURLConnection* strongConnection = self.urlConnection;
if(strongConnection) {
//code to do stuff with the url connection
[strongConnection cancel];
}
I also urge caution with weak references particularly when you have said object handling notifications or observing a change. I've been bitten more than once with the weak object getting destroyed and the notification or observer does not get unregistered.

Why is UIViewController deallocated on the main thread?

I recently stumbled upon The Deallocation Problem in some Objective-C code. This topic was discussed before on Stack Overflow in Block_release deallocating UI objects on a background thread. I think I understand the problem and its implications, but to be sure I wanted to reproduce it in a little test project. I first created my own SOUnsafeObject (= an object which should always be deallocated on the main thread).
#interface SOUnsafeObject : NSObject
#property (strong) NSString *title;
- (void)reloadDataInBackground;
#end
#implementation SOUnsafeObject
- (void)reloadDataInBackground {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.title = #"Retrieved data";
});
sleep(3);
});
}
- (void)dealloc {
NSAssert([NSThread isMainThread], #"Object should always be deallocated on the main thread");
}
#end}]
Now, as expected, if I put [[[SOUnsafeObject alloc] init] reloadDataInBackground]; inside application:didFinishLaunching.. the app crashes after 3 seconds due to the failed assertion. The proposed fix seems to work. I.e. the app doesn't crash anymore if I change the implementation of reloadDataInBackground to:
__block SOUnsafeObject *safeSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
safeSelf.title = #"Retrieved data";
safeSelf = nil;
});
sleep(3);
});
Okay, so it seems like my understanding about the problem and how it can be solved under ARC is correct. But just to be 100% sure.. Let's try the same with an UIViewController (since an UIViewController will probably fill in the role of SOUnsafeObject in real life). The implementation is almost identical to that of the SOUnsafeObject:
#interface SODemoViewController : UIViewController
- (void)reloadDataInBackground;
#end
#implementation SODemoViewController
- (void)reloadDataInBackground {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
self.title = #"Retrieved data";
});
sleep(3);
});
}
- (void)dealloc {
NSAssert([NSThread isMainThread], #"UI objects should always be deallocated on the main thread");
NSLog(#"I'm deallocated!");
}
#end
Now, let's put [[SODemoViewController alloc] init] reloadDataInBackground]; inside application:didFinishLaunching... Hmm, the assertion doesn't fail.. The message I'm deallocated! is printed to the console after 3 seconds so I'm pretty sure the view controller is getting deallocated.
Why is the view controller deallocated on the main thread while the unsafe object is deallocated on a background thread? The code is nearly identical. Does UIKit do some fancy stuff behind the scenes to make sure an UIViewController is always deallocated on the main thread? I'm starting to suspect this since the following snippet also doesn't break my assertion:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
SODemoViewController()
});
If so, is this behavior documented somewhere? Can this behavior be relied upon? Or am I just totally wrong and is there something obvious I'm missing here?
Notes: I'm fully aware of the fact that I can use a __weak reference here, but let's assume the view controller should still be alive to execute our completion code on the main thread. Also, I'm trying to understand the core of the problem here before I circumvent it. I converted the code to Swift and got the same results as in Objective-C (the fix for SOUnsafeObject is there syntactically even uglier).
tl;dr - While I can find no official documentation, the current implementation does indeed ensure that dealloc for UIViewController happens on the main thread.
I guess I could just give a simple answer, but maybe I can do a little "teach a man to fish" today.
OK. I can't find documentation for this anywhere, and I don't remember it ever being said publicly either. In fact, I have always gone out of my way to make sure view controllers were deallocated on the main thread, and this is the first time I've ever seen someone indicate that UIViewController objects get automatically deallocated on the main thread.
Maybe someone else can find an official statement, but I couldn't find one.
However, I do have some evidence to prove that it does indeed happen. Actually, at first, I thought you were not properly handling your blocks or reference counts, and somehow a reference was being retained on the main thread.
However, after a cursory look, I was interested enough to try it for myself. To satisfy my curiosity, I made a class similar to yours that inherited from UIViewController. Its dealloc ran on the main thread.
So, I just changed the base class to UIResponder, which is the base class of UIViewController, and ran it again. This time its dealloc ran on the background thread.
Hmmm. Maybe there is something going on behind closed doors. We have lots of debugging tricks. The answer always lies with the last one you try, but I figured I'd try my usual bag of tricks for this kind of stuff.
Log Notifications
One of my favorite tools to find out how things are implemented is to log all notifications.
[[NSNotificationCenter defaultCenter]
addObserverForName:nil
object:nil
queue:nil
usingBlock:^(NSNotification *note) { NSLog(#"%#", note); }];
I then ran using both classes, and didn't see anything unexpected or different between the two. I didn't expect to, but that little trick is very simple, and it has helped me tremendously in discovering how a lot of other things worked, so it's usually first.
Log Method/Message Sends
My second trick it to enable method logging. However, I don't want to log all methods, just what happens between the time the last block executes, and the call to dealloc. So, turned on method logging by adding this as the last line of the "sleeping" block.
instrumentObjcMessageSends(YES);
And I turned logging back off, with this as the first line of the dealloc method.
instrumentObjcMessageSends(NO);
Now, this C function can't be readily found in any headers that I know of, so you need to declare it at the top of your file.
extern void instrumentObjcMessageSends(BOOL);
The logs go into a unique file in /tmp, named msgSends-.
The files for the two runs contained the following output.
$ cat msgSends-72013
- __NSMallocBlock__ __NSMallocBlock release
- SOUnsafeObject SOUnsafeObject dealloc
$ cat msgSends-72057
- __NSMallocBlock__ __NSMallocBlock release
- SOUnsafeObject UIViewController release
- SOUnsafeObject SOUnsafeObject dealloc
There is not too much surprising about that. However, the presence of UIViewController release indicates that UIViewController has a special override implementation for the +release method. I wonder why? Could it be to specifically transfer the call to dealloc to the main thread?
Debugger
Yes, this is the first thing I thought of, but I had no evidence that there was an override in UIViewController so I went through my normal process. I have found when I skip steps, it typically takes longer.
Anyway, now that we know what we are looking for, I put a breakpoint on the last line of the "sleeping" block and made the class inherit from UIViewController.
When I hit the breakpoint, I added a manual breakpoint...
(lldb) b [UIViewController release]
Breakpoint 3: where = UIKit`-[UIViewController release], address = 0x000000010e814d1a
After continuing, I was greeted with this awesome assembly, which confirms visually what is happening.
pthread_main_np is a function that tells you if you are running on the main thread. Stepping through the assembly instructions confirmed that we are not running on the main thread.
Stepping further, we get to line 27, where we jump over the call to dealloc, and instead run what you can easily see is code to run a dealloc-helper on the main thread.
Can You Count on This Going Forward?
Since I can't find it documented, I don't know that I would count on this happening all the time, but it is very convenient, and obviously something they intentionally put into the code.
I have a set of tests that I run every time Apple releases a new version of iOS and OSX. I assume most developers do something very similar. I think what I would do is write a unit test, and add it to that set. Thus, if they ever change it back, I'll know as soon as it comes out.
Otherwise, I tend to think this may be one of those things that can safely be assumed.
However, be aware that subclasses may choose to override release (if they are compiled with ARC disabled), and if they do not call the base class implementation, you will not get this behavior.
Thus, you may want to write tests for any third-party view controller classes you use.
My Details
I only tested this with XCode 6.4, Deployment target 8.4, simulating iPhone 6. I'll leave testing with other versions as an exercise for the reader.
BTW, if you don't mind, what are the details for your posted example?

Observing values for a primitive pointer

I have a class with a property
#property (nonatomic) double* myDoubles
This property has 3 doubles in it
myDoubles[0]; //0.02
myDoubles[1]; //0.42
myDoubles[2]; //0.99
If the values change, I'd like the following method to be called
[self setNeedsDisplay];
I tried using FBKVOController, but that didn't work..
_observer = [FBKVOController controllerWithObserver:self];
[_observer observe:self
keyPath:#"myDoubles"
options:NSKeyValueObservingOptionNew
action:#selector(setNeedsDisplay)];
I don't want to start an NSTimer and just check for changes.
This is not possible.
Notifications work because the code making changes does so through some method that knows to notify listeners of the change. If that same code were simply to write to the memory location backing the data, the notification would never be triggered.
What you want to do is simply declare a memory location that code will write to; no notification can happen from this (unless you have very system-dependent support making it possible - a memory watchpoint - and then your question changes significantly. Such support, when available, is very limited and not of good generic value).

Memory Management in a Block Using Notifications

According to the Xcode instruments, my code has a memory leak (at #3). But I get the feeling I'm missing something in my mental model of what's going on, so I have a few questions about the following logic:
__block MyType *blockObject = object; //1
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.selectedObjects containsObject:blockObject]) { //2
[self.selectedObjects removeObject:blockObject];
[[NSNotificationCenter defaultCenter] postNotificationName:ObjectDeselectionNotification object:blockObject]; //3
} else {
[self.selectedObjects addObject:blockCart];
[[NSNotificationCenter defaultCenter] postNotificationName:ObjectSelectionNotification object:blockCart];
}
});
1) I'm using a __block reference because I'm executing this code async and don't want a reference to this variable copied to the heap. Is this a valid usage of __block even though I'm not mutating the variable?
2) Calling self.selectedObjects will create a retain on self. Does the block automatically release this after it has exited?
3) I apparently have a leak at this point, but I'm not exactly sure why. Is NotificationCenter retaining my __block object that is supposed to be disposed of after my block exits?
From the code you've shown, I don't see any problems...
1) Your object would not be "copied" onto the heap - it is already on the heap being an alloc'd object. Rather, it's reference count would be incremented by 1 as it is now owned by the block. You do not need the __block reference as you are not assigning anything to the pointer. In fact, you do not need blockObject at all and can just pass object.
2.) self should be released once the block is done. However, post a notification is synchronous (this block will not finish until all the objects responding to the notification are done).
3.) I'm not sure what the exact implementation that NSNotificationCenter uses, but it doesn't really matter because the posting is synchronous. It will call every observer of your notification and the selectors they want to receive your notification on
It seems as though you are running all this code within another block - can you paste the full method?
Please remove this answer if incorrect (you've already accepted) but I'm not sure you accepted because the answer worked for you.
I don't think you should be referencing self in that block - you will be creating a retain cycle.
__weak YourClass *weakSelf = self;
use weakSelf instead and cut the tie between the creator and the block floating on the dispatch queue?

Reachability Classes crashing program - not sure why

I have an 'internet aware' base class for objects which require networking in my app. All the objects which need to be internet aware inherit from it. As you can imagine I allocate and deallocate a lot of these objects.
The internet aware base class has the following code to interact with the Reachability classes used to check for internet status.
#import "Reachability.h"
- (id) init {
...
self.internetReachable = [Reachability reachabilityForInternetConnection];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkNetworkStatus) name:kReachabilityChangedNotification object:nil];
[self.internetReachable startNotifier];
...
}
- (void) dealloc
{
[self.internetReachable stopNotifier];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
As soon as there is a change in internet status in my app, the app crashes with the following error:
*** -[Reachability isKindOfClass:]: message sent to deallocated
instance 0x1e249a30
Ive turned on zombies and tracked the problem down to the following line of code within Reachability.m
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], #"info was wrong class in ReachabilityCallback");
Unfortunately, beyond stopping listening for NSNotifcations and stopping the notifier, im not sure what else my objects can do to avoid this error.
Any help or suggestions would be great.
Thanks
Vb
Edit:
OK so following the advice of the answer below I ran it in instruments with allocations
and this was the retain count history.
It is as I suspected, its an object that I have deallocated being called by Foundation (ie. NSNotifcationCenter) and not myself.
My internet objects have a strong pointer to a Reachability object. When they are deallocated, so is the Reachability object. The zombie is the Reachability object.
In the dealloc of my internet object I have called removeObserver, but foundation is still calling the deallocated object. I can't understand why...
The reason that Foundation was still sending the deallocated Reachability the NSNotifcations was because the Reachability object was being deallocated on a different thread to the one it was being created on ie. Reachability isn't thread safe. Using dispatch_async back to the same queue that the Reachability object was being created on has solved the problem.
This happens when the object you made that instantiates Reachability, and hence holds a reference to a Reachability instance, is deallocate without (or before) you call stopNotifier on it!
Solving this is very simple. You must call stopNotifier before your object gets removed from the stack tearing down your Reachability instance with it. You can do this in the dealloc method, or if it's a viewController, you could call it in one of the lifecycle methods such as viewDidDisappear, etc.
There should be no need of messing with threads here. Consider, when you call startNotifier on Reachability this thing starts on a background thread by design of Reachability. So, when you call stopNotifier it takes care of threading for you.
The reason you're having to mess with threads has to do with the fact that your object holding the reference to Reachability got deallocated but was still a registered listener for network changes, which happened with startNotifier. When the network does change, guess what, your object, although still registered to receive notifications, is nowhere to be found! Crashy crash. stopNotifier unregisters it before it dies and everything is good.
- (void)dealloc
{ // self.hostReachability is my property holding my Reachability instance
if (self.hostReachability) {
[self.hostReachability stopNotifier];
}
}
The NSCAssert line is where you first access the deallocated object, but if you want to know more about the object's life cycle you should use Instruments. Use Xcode's Profile tool to run your program in the simulator with the Allocations (but not leaks!) tool. In the allocations tool's launch configuration turn on Enable NSZombie Detection and Record Reference Counts. When you hit the NSCAssert line Instruments should detect the attempt to message the zombie info object and make a note of it. If you look at the detailed information for the zombie info object Instruments will show you its history of reference counts and you should be able to see when it was deallocated.

Resources