What is the lifetime of an object declared in a block under ARC? - objective-c

There is a gap in my understanding of blocks and ARC that I would like some help with. I have received a crash report from a tester which originates from an animation completion block. The crash is as follows:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0xf0000010
This is happening inside the following animation completion block (using animateWithDuration:animations:completion:). I am swapping two view controllers using a temporary variable:
{
[current wasMovedOffScreen];
PlayerViewController *temp = current;
current = next;
next = temp;
}
next = temp; is the line on which the crash occurs. The duration of the animation is 0.3 seconds.
This code is executed inside a view controller which acts as a container for two other view controllers, used to simulate the user passing through a list of objects, like a navigation controller, but with a number of customisations that meant a navigation controller was not appropriate for me.
The two child view controllers are called "current" and "next" - as you can guess the current controller displays the current content, and the next one is used to animate in the new item when the user moves through the list.
If I change the block so that temp is declared in the implementation (along with current and next) the crash stops. However it seems unnecessary to me to have to hold a class ivar for something that is by definition local and temporary.
So,
Why is temp apparently released by ARC during this process?
What would be the correct way to implement this? Is there some lifetime qualifier I should add to the block implementation?
Why could I not reproduce the crash on my own device or in the simulator? Both devices were iPhone 4 running the same version of iOS (5.0.1).

I don't think the problem is actually ARC in this instance. Variables (including local variables) are __strong by default, so current should be retained in the first assignment.
http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html - see section 'Variable Qualifiers'
If you've got a crash you can't reproduce yourself, it's always going to be difficult to fix. Have you tried running the app outside of the debugger? Having the debugger loaded can sometimes change behaviour. Also, try debugging with NSZombieEnabled, or Instruments.app's zombie tool.

And if it really keeps you up, since you're only alternating between two views you don't actually need all this current / next business. Well, you can keep track of current if you want... but here's the idea.
If you have properties:
#property (nonatomic, strong) UIViewController *controller1;
#property (nonatomic, strong) UIViewController *controller2;
#property (nonatomic, weak) UIViewController *currentController;
Then you can have a method:
- (id)swapControllers {
// use the current controller to figure out what the next controller is, so
// you don't have to do the two way swap. do in the completion, if you like.
UIViewController *nextController = ([self.currentController isEqual:self.controller1]) ? self.controller1 : self.controller2;
[UIView animateWithDuration:.25
animations:^{
// TODO: some animations on currentController and nextController
} completion:^(BOOL finished) {
[self.currentController wasMovedOffScreen];
self.currentController = nextController;
}];
}
As for your original issue, ARC knows how to handle blocks pretty well - if you weren't using it, I might ask if you'd forgotten to copy a block declared elsewhere, then stored, then passed in as the completion handler. Since that's not the case, and since you haven't been able to get a repro... I'm guessing that you might be running a beta sdk - there have been some ARC bugs in beta releases of late. If that's so, you might try building with the last stable release, and see if you get better results.

Related

Is it ever Ok to have a 'strong' reference for a delegate?

I have a class that retrieves JSON from a URL and returns the data via the protocol/delegate pattern.
MRDelegateClass.h
#import <Foundation/Foundation.h>
#protocol MRDelegateClassProtocol
#optional
- (void)dataRetrieved:(NSDictionary *)json;
- (void)dataFailed:(NSError *)error;
#end
#interface MRDelegateClass : NSObject
#property (strong) id <MRDelegateClassProtocol> delegate;
- (void)getJSONData;
#end
Note that I'm using strong for my delegate property. More about that later...
I am trying to write a 'wrapper' class that implements getJSONData in a block-based format.
MRBlockWrapperClassForDelegate.h
#import <Foundation/Foundation.h>
typedef void(^SuccessBlock)(NSDictionary *json);
typedef void(^ErrorBlock)(NSError *error);
#interface MRBlockWrapperClassForDelegate : NSObject
+ (void)getJSONWithSuccess:(SuccessBlock)success orError:(ErrorBlock)error;
#end
MRBlockWrapperClassForDelegate.m
#import "MRBlockWrapperClassForDelegate.h"
#import "MRDelegateClass.h"
#interface DelegateBlock:NSObject <MRDelegateClassProtocol>
#property (nonatomic, copy) SuccessBlock successBlock;
#property (nonatomic, copy) ErrorBlock errorBlock;
#end
#implementation DelegateBlock
- (id)initWithSuccessBlock:(SuccessBlock)aSuccessBlock andErrorBlock:(ErrorBlock)aErrorBlock {
self = [super init];
if (self) {
_successBlock = aSuccessBlock;
_errorBlock = aErrorBlock;
}
return self;
}
#pragma mark - <MRDelegateClass> protocols
- (void)dataRetrieved:(NSDictionary *)json {
self.successBlock(json);
}
- (void)dataFailed:(NSError *)error {
self.errorBlock(error);
}
#end
// main class
#interface MRBlockWrapperClassForDelegate()
#end
#implementation MRBlockWrapperClassForDelegate
+ (void)getJSONWithSuccess:(SuccessBlock)success orError:(ErrorBlock)error {
MRDelegateClass *delegateClassInstance = [MRDelegateClass new];
DelegateBlock *delegateBlock = [[DelegateBlock alloc] initWithSuccessBlock:success andErrorBlock:error];
delegateClassInstance.delegate = delegateBlock; // set the delegate as the new delegate block
[delegateClassInstance getJSONData];
}
#end
I've come to the objective-c world relatively recently (only lived in ARC times, and still coming to terms with blocks) and admittedly my understanding of memory management is on the slimmer side of things.
This code seems to work fine, but only if I have my delegate as strong. I understand that my delegate should be weak to avoid potential retain-cycles. Looking in instruments, I find that allocations do not continue to grow with continued calls. However, I believe 'best practice' is to have weak delegates.
Questions
Q1) is it ever 'ok' to have strong delegates
Q2) how could I implement the block-based wrapper leaving the delegate of the underlying class as weak delegate (ie. prevent the *delegateBlock from being deallocated before it receives the protocol methods)?
Q1 - Yes. As you point out yourself having delegate properties being weak is a recommendation to help avoid retain cycles. So there is nothing wrong per se with having a strong delegate, but if the clients of your class expect it to be weak you may cause them surprises. The better approach is to keep the delegate weak and for the server side (the class with the delegate property) to keep a strong reference internally for those periods it needs one. As #Scott points out Apple documents doing this for NSURLConnection. Of course that approach doesn't solve your issue - where you want the server to retain the delegate for you...
Q2 - Looked at from the client side the problem is how to keep a delegate alive as long as a server with a weak reference to it requires it. There is a standard solution to this problem called associated objects. In brief the Objective-C runtime essentially allows a key-collection of objects to be associated with another object, along with an association policy which states how long that association should last. To use this mechanism you just need to pick your own unique key, which is of type void * - i.e. an address. The following code outline shows how to use this using NSOpenPanel as an example:
#import <objc/runtime.h> // import associated object functions
static char myUniqueKey; // the address of this variable is going to be unique
NSOpenPanel *panel = [NSOpenPanel openPanel];
MyOpenPanelDelegate *myDelegate = [MyOpenPanelDelegate new];
// associate the delegate with the panel so it lives just as long as the panel itself
objc_setAssociatedObject(panel, &myUniqueKey, myDelegate, OBJC_ASSOCIATION_RETAIN);
// assign as the panel delegate
[panel setDelegate:myDelegate];
The association policy OBJC_ASSOCIATION_RETAIN will retain the passed in object (myDelegate) for as long as the object it is associated with (panel) and then release it.
Adopting this solution avoids making the delegate property itself strong and allows the client to control whether the delegate is retained. If you are also implementing the server you can of course provide a method to do this, maybe associatedDelegate:?, to avoid the client needing to define the key and call objc_setAssociatedObject itself. (Or you can add it to an existing class using a category.)
HTH.
It entirely depends on the architecture of your objects.
When people use weak delegates, it's because the delegate is usually some kind of "parent" object, which retains the thing that has the delegate (let's call the "delegator"). Why does it have to be a parent object? It doesn't have to be; however, in most use cases it turns out to be the most convenient pattern. Since the delegate is a parent object that retains the delegator, the delegator can't retain the delegate or it will have a retain cycle, so it holds a weak reference to the delegate.
However, that is not the only use situation. Take, for example, UIAlertView and UIActionSheet in iOS. The usual way that they are used is: inside a function, create an alert view with a message and add buttons to it, set its delegate, perform any other customization, call -show on it, and then forget it (it is not stored anywhere). It's a kind of "fire and forget" kind of mechanism. Once you show it, you don't need to retain it or anything and it will still be displayed on screen. It's possible in some cases you might want to store the alert view around so you can programmatically dismiss it, but that is rare; in the vast majority of use cases, you simply show and forget it, and just handle any delegate calls.
So in this case, the proper style would be a strong delegate, because 1) the parent object does not retain the alert view, so there is no issue with a retain cycle, and 2) the delegate needs to be kept around, so that when some button is pressed on the alert view, someone will be around to respond to it. Now, a lot of times, #2 isn't a problem because the delegate (parent object) is some kind of view controller or something that is otherwise retained by something else. But this is not always the case. For example, I can simply have a method that is not part of any view controller, which anyone can call to show an alert view, and if the user presses Yes, uploads something to the server. Since it's not part of any controller, it likely is not retained by anything. But it needs to stay around long enough until the alert view is done. So ideally the alert view should have a strong reference to it.
But as I've mentioned before, this is not always what you want for an alert view; sometimes you want to keep it around and dismiss it programmatically. In this case, you want a weak delegate or it will cause a retain cycle. So should an alert view have a strong or weak delegate? Well, the caller should decide! In some situations the caller wants strong; in others the caller wants weak. But how is this possible? The alert view delegate is declared by the alert view class, and must be declared as either strong or weak.
Fortunately, there is a solution that does let the caller decide -- a blocks-based callback. In a blocks-based API, the block essentially becomes the delegate; but the block is not the parent object. Usually the block is created in the calling class and captures self so that it can perform actions on the "parent object". The delegator (alert view in this case) always has a strong reference to the block. However, the block may have a strong or weak reference to the parent object, depending on how the block is written in the calling code (to capture a weak reference to the parent object, don't use self directly in the block, and instead, create a weak version of self outside the block, and let the block use that instead). In this way, the calling code fully controls whether the delegator has a strong or weak reference to it.
You are correct in that delegates are usually weakly referenced. However, there are use cases where a strong reference is preferred, or even necessary. Apple uses this in NSURLConnection:
During a download the connection maintains a strong reference to the delegate. It releases that strong reference when the connection finishes loading, fails, or is canceled.
An NSURLConnection instance can only be used once. After it finishes (either with failure or success), it releases the delegate, and since the delegate is readonly, it can't be (safely) reused.
You can do something similar. In your dataRetrieved and dataFailed methods, set your delegate to nil. You probably don't need to make your delegate readonly if you want to reuse your object, but you will have to assign your delegate again.
As other said it's about architecture. But I'll walk you through it with several examples:
Retry upon failure
Suppose you've made a URLSession, and are waiting for a network call you made through a viewController, sometimes it doesn't matter if it failed, but at other times it does. e.g. you're app is sending a message to another user, then you close that viewcontroller and somehow that network request fails. Do you want it to retry again? If so then that viewController has to remain in memory, so it can resubmit the request again.
Writing to disk
Another case would be when a request succeeds you may want to write something to the disk, so even after the viewcontroller has its UI updated you might still want to sync your local database with the server.
Large background tasks
The original use case for NSURLSession was to power background network task execution, large file downloads and things of that nature. You need something in memory to handle the finalization of those tasks to indicate execution is complete and the OS can sleep the app.
Associating the lifecycle of downloading large files to a certain view is a bad idea…it needs to be tied to some more stable/persistent e.g. the session itself…
Normally if I’m going to use the delegate based system rather than URLSession’s newer block-based API, I have a helper object that encapsulates all the logic necessary to handle failure and success cases that I may require that way, I don’t have to rely on a heavy VC to do the dirty works
This is answer was entirely written thanks to a conversation I had with MattS

Protecting my code from zombies from completion blocks

I'm familiar with the delegate pattern and nilling my delegates, especially when doing asynchronous calls which are still in progress when my view controllers disappear. I nil the delegate, and the callback successfully returns on a nil object.
I'm now experimenting with using completion blocks to make my code a little easier to read.
I call a network service from my view controller, and pass a block which updates my UITableView. Under normal circumstances it works fine. However, if I leave the view before it completes, the completion handler block is executed - but the UITableView is now a zombie.
Whats the usual pattern for handling this?
UPDATE WITH CODE SAMPLE
This is an iPad app, I have two view controllers on screen at once, like a split view. One is the detail, and the other is a grid of images. I click an image and it tell the detail to load the info. However, if i click the images too fast before they have chance to do the network call - I have the problems. On changing images the code below is called which counts the favourites of a image....
So here is my dilemma, if I use the code below - it works fine but it leaks in instruments if you switch images before the network responds.
If I remove the __block and pass in self, then it crashes with zombies.
I can't win... I'm sure i'm missing something fundamental about using blocks.
__block UITableView *theTable = [self.table retain];
__block IndexedDictionary *tableData = [self.descriptionKeyValues retain];
FavouritesController *favourites = [Container controllerWithClass:FavouritesController.class];
[favourites countFavouritesForPhoto:self.photo
completion:^(int favesCount) {
[tableData insertObject:[NSString stringWithFormat:#"%i", favesCount]
forKey:#"Favourites:" atIndex:1];
[theTable reloadData];
[tableData release];
[theTable release];
}];
Any tips? Thanks
SECOND UPDATE
I changed the way I loaded the favourites. Instead of the favourites being a singleton, I create an instance on each photo change. By replacing this and killing the old one - the block has nowhere to callback (i guess it doesn't even exist) and my code now just looks like the below, and it appear to be working:
[self.favourites countFavouritesForPhoto:self.photo
completion:^(int favesCount) {
[self.descriptionKeyValues insertObject:[NSString stringWithFormat:#"%i", favesCount]
forKey:#"Favourites:" atIndex:1];
[self.table reloadData];
}];
It doesn't leak, and doesn't appear to be crashing either.
I recommend you test that the tableview is not nil at the start of the block. It sounds like the tableview is properly discarded when its parent view goes off-screen, so after that point, no tableview operations are valid.
Retaining the UITableView within the block is a bad idea, because datasource/tableview updates can result in implicit method calls and notifications that will not be relevant if the tableview is not on-screen.
Block will retain any object that it references, except for those annotated with __block. If you want not to execute completion blocks at all, just make some property like isCancelled and check whether it is YES before calling completion block.
So you have a background operation which has to call back another object after it finishes and the object can be destroyed in the meantime. The crashes you describe happen when you have non retained references. The problem as you see is that the referred object goes away and the pointer is invalid. Usually, what you do is unregister the delegate inside the dealloc method so that the background task continues, and whenever it is ready to communicate the results back it says "Shoot, my callback object is nil", and at least it doesn't crash.
Still, handling manually weak references is tedious and error prone. You can forget to nil a delegate inside a dealloc method and it may go without notice for months before you encounter a situation where the code crashes.
If you are targeting iOS 5.0 I would read up upon ARC and the weak references it provides. If you don't want to use ARC, or need to target pre 5.x devices, I would recommend using zeroing weak reference libraries like MAZeroingWeakRef which work also for 3.x devices.
With either ARC's weak references or MAZeroingWeakRef, you would implement the background task with one of these fancy weak reference objects pointing back to your table. Now if the pointed object goes away, the weak pointer will nil itself and your background task won't crash.

viewDidLoad vs appDelegate methods

I persist to be a little confused about when to put something in a viewController and when to put it inside an AppDelegate, and if it is ok to reference viewController methods from the AppDelegate (i know you can but that doesn't mean it is encouraged).
Really, I wouldn't be confused if it weren't for all this multi-tasking stuff that seems to complicate the concepts for me. First, if anyone knows of a good, thorough and easy to read overview of how to deal with multitasking, I'd love to know.
Here's the deal: there are things I need my app to do when it loads, whether loading fresh or loading from the background. Stuff like perform a network reachability test, setup the interface based on data received from the internet, and this or that.
One of my main questions relates to how the viewcontroller's view interacts with background states. If the app resumes from the background and the view is immediately present without loading, then I assume it is still in memory and I have verified that viewDidLoad was not called with a basic NSLog. So, is it safe to say that any and all objects retained by my viewcontroller (like the data models and all subviews) are thus still in memory? If not, what's the best practice discovering which objects need to be re-loaded, what are still there, etc?
I think it's safe to assume that the standard memory management rules apply, even in a multi-tasking environment. That means that your controller, and anything you've got a reference to in your controller should still be valid until either:
You explicitly deallocate your controller/objects
Your app terminates
It seems like your assumption is that the system is going to mess with your objects behind your back, which (I hope) can't happen. Those methods are there in the app delegate in case you want to explicitly do anything when those particular events occur.
Regarding the viewDidLoad question, you could implement viewDidUnload or check the isViewLoaded method to make sure your view wasn't unloaded due to a low memory condition or otherwise. More on this in the UIViewController documentation.
One way to approach this problem is with lazily-loaded properties. In your .h file:
#interface YourViewController : NSObject
#property (nonatomic, retain) NSArray *exampleObject;
#end
And in your .m file:
#implementation YourViewController
#synthesize exampleObject = _exampleObject;
- (NSArray *)exampleObject {
// reload only if necessary
if (!_exampleObject) {
_exampleObject = [[NSArray alloc] init];
// do whatever other setup you need to
}
return _exampleObject;
}
#end

Cocoa ivar losing value between init and drawRect

I am not a complete n00b here, but I feel like I must be missing something essential. I'm passing a variable into a new class instance via the class's init method:
#synthesize side;
- (id)initWithSide:(NSString *)aSide frame:(NSRect)frameRect
{
if (self = [super initWithFrame:(NSRect)frameRect]) {
self.side = aSide;
}
NSLog(#"Side is %#", self.side);
return self;
}
The output from NSLog() does show the correct value here. Now, the drawRect: method that is then triggered to draw the view, has a similar call:
- (void)drawRect:(NSRect)rect
{
NSLog(#"Side is %#", self.side);
And this time the NSLog() reports Side as nil! Stepping through it with the debugger, I see the value for side gets set, then it goes into the registers (all those hex codes that I don't understand), then when it jumps out again into the drawRect: method, the value is simply nil.
If anyone can shed light on this I'd appreciate it!
Cheers,
Aaron
This is usually the way to write a property for NSString*.
assign is used for primitive types (it doesn't increment the retain count for an object), and either retain or copy for Objects.
#property (readwrite, copy) NSString * side
I'm going to go ahead and guess the most common cause for this kind of bug: You're dealing with two different objects. You're initializing the view in your code and you also have an instance in a nib. The two instances are completely separate objects, so when the view that is visible performs its drawRect:, it doesn't see the other one's instance variable.
The problem with your property that other people are pointing out is also definitely true, but I suspect this bug is actually hiding that one.

UINavigationController crash because of pushing and poping UIViewControllers

The issue:
I have a UINavigationController as as subview of UIWindow, a rootViewController class and a custom MyViewController class. The following steps will get a Exc_Bad_Access, 100% reproducible.:
[myNaviationController pushViewController:myViewController_1stInstance animated:YES];
[myNaviationController pushViewController:myViewController_2ndInstance animated:YES];
Hit the left back tapBarItem twice (pop out two of the myViewController instances) to show the rootViewController.
After a painful 1/2 day of try and error, I finally figure out the answer but also raise a question.
The Solution: I declared many objects in the .m file as a lazy way of declaring private variables to avoid cluttering the .h file. For instance,
#impoart "MyViewController.h"
NSMutableString*variable1;
#implement ...
-(id)init
{
...
varialbe1=[[NSMutableString alloc] init];
...
}
-(void)dealloc
{
[variable1 release];
}
For some reasons, the iphone OS may loose track of these "lazy private" variables memory allocation when myViewController_1stInstance's view is unloaded (but still in the navigation controller's stacks) after loading the view of myViewController_2ndInstance. The first time to tap the back tapBarItem is ok since myViewController_2ndInstance'view is still loaded. But the 2nd tap on the back tapBarItem gave me hell because it tried to dealloc the 1st instance. It called [variable release] resulted in Exc_Bad_Access because it pointed randomly (loose pointer).
To fix this problem is simple, declare variable1 as a #private in the .h file.
Here is my Question:
I have been using the "lazy private" variables for quite some time without any issues until they are involved in UINavigationController. Is this a bug in iPhone OS? Or there is a fundamental misunderstanding on my part about Objective C?
It might be related to both instances of your view controller using the same statically-allocated variable.
In other words, both myViewController_1stInstance and myViewController_2ndInstance are using the same variable1 location in memory and overwriting one another.
Variables declared inside of the curly braces after your #interface definition have a memory location allocated by the runtime for each instance of the class (every time you call [<ClassName> alloc]. Variables declared in the global scope (that is, outside of any functions or class declarations) are just that: global. That means that the variable can only hold one value per running copy of your application.
There are no truly private variables in Objective-C, but you can hide them from other instances at compile time as described here.
A bit of a late reaction, but I've seen this problem before. Don't push two viewControllers animated at the same time. Push the first one without animation and push the second one with animation. UINavigationController can't handle two animations at the same time.