Message was sent to a deallocated object (ARC) - ios

In my app I've a UITableView in which I have custom UITableViewCells and those cells contain UIWebView in which I am displaying YouTube video using <iframe>. When I click on a video and instantly scroll the table before a full screen player opens, the app crashes. I tried Instruments to find the problem and came to know that An Objective-C message was sent to a deallocated 'AAHomeNewsListCell' object (zombie) at address: 0x118e09800.

I'm using ARC and I can't find a way to resolve this issue.

You are sending a message to an object that is no longer alive. The best way to debug that problem would probably be to set a break point as close as you can to where the situation happens, and step through the code. A good place to start would be close to where you use an AAHomeNewsListCell-object, or close to where you trigger the full screen player.

If I had to guess, I'd say that the web view is messaging its delegate but the delegate has already been deallocated. UIWebViewDelegate comes with this handy warning:
Important: Before releasing an instance of UIWebView for which you have set a delegate, you must first set the UIWebView delegate property to nil before disposing of the UIWebView instance. This can be done, for example, in the dealloc method where you dispose of the UIWebView.
Looking at your zombie message, what is it that would be still trying to message the cell? Is your cell acting as the web view's delegate?
Edit Looking at what message is being sent, it gets _setFirstResponder:. It could be a text entry form in the web view that's trying to get first responder to enter text.

Related

How to restore UIInputViewController self.view after dismissing the keyboard?

I'm developing an application that has an Keyboard extension, At some uses of the Keyboard extension (for example: when I use the switch keyboard button) the extension is going through the viewDidDisappear and at this case I know I can clean the keyboard and it's getting deallocated with all it's views and the memory is freed. At other uses (for example: when using the Notes application and pressing the Done/Back button) the extension is going through the viewWillDisappear but not through the viewDidDisappear, So in this case I'm not cleaning the Keyboard as it's not reaching my cleaning methods and therefore it's not getting deallocated.
At this point I would expect that when I return to the keyboard by going back to the note for example I would receive the previous UIInputViewController with the view I already built.
Unfortunately at this point the isViewLoaded() method returns false and my UIInputViewController is going again through the loadView method therefore building again all the views all over again, as a result the application memory grows until at some point I reach the nasty didReceiveMemoryWarning method callback.
I would like to restore somehow the view I created for my keyboard in the UIInputViewController that was initialized first. Does some one know is it possible and how could this be achieved?
I was looking into the restorationIdentifier to accomplish this task, correct me if I'm wrong but this is used with an ordinary UIViewController and can't be used with the UIInputViewController as not my AppDelegate is responsible to launch it.
Update
From further research I made, I came to a conclusion that no matter what the operation you commit:
Use Done/Back button in the Notes application.
Switch to the Messages app and use the keyboard there.
Use the “switch keyboard" button
And other scenarios, the UIInputViewController class always goes through the init method.
From my understanding of the object oriented programming this mean that whoever calls my keyboard to reaper does it using the constructor and basically creates a new instance of the keyboard. That means that I will never have an available view on first reappearance of the keyboard in any of the behaviors and I always have to build the keyboard view for the new instance and cleanup the old one. Is this right? or there is a way to presereve the view of the UIInputViewController?
Unless you're using your own custom application with the keyboard to store its previous instance, there's no way to do this. In everything besides a custom application designed by you, it is beyond your scope

How can I keep track and control which views deallocates?

When my app is launched, it starts out at a custom UIViewController with a custom UITableView with custom UITableViewCells. The cells can play videos, among other things. I'm using AVPlayer and AVPlayerLayer to play the videos. This initial view controller also has a menu-popup, which can take you to another controller. When another menu-option is clicked, the initial UIViewController deallocates. This is on purpose, and setting the new UIViewController as the applications rootViewController. However, if I start playing a video in a cell in the initial viewController and then click a menu-option, the video keeps playing in the background, I can still hear the audio.
I have simply put
-(void)dealloc{
NSLog(#"Initial controller deallocated");
}
in the initial view controller to confirm that it deallocs when I set the new controller as root, and this prints out, but the video still keeps playing.
I have now 'overridden' the -(void)dealloc(like above) methods of both the custom UITableView and the custom UITableViewCell's, but neither of these fires.
I have simplified the explanation of the hierarchy here, and I believe there could be other connections holding on to the tableView(mostly because I don't know any other reason for this behavior).
I believe, however, that these possible connections all are under the initial view controllers hierarchy, and it is my understanding that the entire hierarchy under a view controller will vanish when the view controller does. Is the AVPlayer a reason the tableView and/or cell won't dealloc? The videos playing are over internet, and I can also tell that the app continues downloading and buffering the video after the controller has been deallocated. I have tried setting the player, the playerLayer and the entire cell to nil, but it keeps downloading, and I'm thinking I have misunderstood some connections.
First of all, I think properties with (strong, nonatomic) or (nonatomic, retain) might have something to do with these. I don't completely understand where to use what, so I almost exclusively use this. Of what I'm reading, weak seems to be correct for some of these references, but I'm also 'scared' of the implications, as I don't completely understand them.
Second, in my custom UITableView, I have a property: #property CustomCell *playing;.
When I start playing a video in a specific cell, like this;
[someSpecificCell.player play]; I also do this: self.playing = someSpecificCell;. Now I can later easily find the cell that's playing, I.E to stop it. When I later try to deallocate the cell, I use self.playing = nil;, however, this does not deallocate the cell. Why not? Am I simply removing the reference from tableView? Does this mean there are other references?
Is there a way to see a list of where these references are /from? As far as I know, all references are in the same initial hierarchy, yet somehow some parts of the hierarchy stays alive after their controller has deallocated.
Update
I've now tried to launch Instruments with the Allocations-tool, and I don't completely understand what I'm seeing.
The hierarchy I've created is something like this:
MyNavController1->MyViewController1->MyView1->MyTableView1->MyCell1->text&video etc.
When I click another menu-option, I create another (almost identical) hierarchy, setting the new MyNavController(2) as rootViewController for the app. The 'current' hierarchy will now be
MyNavController2->MyViewController2->MyView2->MyTableView2->MyCell2->something else
When I present the new hierarchy, and set this new hierarchy as rootViewController to the app, the first hierarchy is supposed to be deallocated. In -(void)dealloc of both MyNavController1 and MyViewController1 print out "Deallocated" with NSLog();, and nothing from MyTableView1 and MyCell1.
In Instruments it says that MyViewController is #living: 1, #transient: 1, which I'm guessing means the first deallocated correctly.
When I check the field for MyTableView, it says #living: 2, #transient: 0, which I'm guessing means the tableView isn't deallocated, as my previous "research" found.
However, in the list showing the two instantiations of MyTableView, it says that the responsible caller of the first tableView(which is supposed to be deallocated, but isn't) is the first MyViewController1, which is confirmed deallocated. What does this mean?
If I further click the Address field of this specific MyTableView(the first), it says:
# Event Type ΔRefCt: RefCt ... Responsible Caller
0 Malloc +1 1 ... 'MyViewController1'
What does this really mean, and can I find out where a possible reference is held?

Strange behaviour while deallocation of an object

I have a view, which is subclass of UIWebView. It has a property called Contact which is a managed object. The view uses templating engine to create a html with the object and then load into UIWebView. I thought it would be a better idea to monitor the object in the view itself, such that whenever something changes in the object, the view refreshes automatically. So, observed for certain attributes of the managed object in the view itself. And then to avoid the notification coalesce, I have made it such that the reload is done with
[self performSelector:#selector(refresh) afterDelay:0 ].
It refresh the webview automatically whenever it finds the change but also gives some strange crash. The crash says [MyWebView retain] message sent to deallocated object. I know I have properly removed observing values in dealloc method. But, it seems like dealloc gets triggered after a while. I have a strange issue related to releasing the view. The view stays for a while, although the view controller is already released and then releases after may 2/3 seconds. It is really strange. I think the crash is because of this.
Please do suggest me any idea. I will be glad to hear your suggestion. There are something wrong certainly, if anybody could point me I would really be grateful.
Using the delegate design pattern can cause EXC_BAD_ACESS KERN_INVALID_ADDRESS crashes if not used properly. If you have processing that is running in background threads that use the delegate design pattern, where in the object you set SELF as the delegate then you must remove SELF as the delegate in the dealloc method (even under ARC) by setting the delegate reference to nil, or there is a possibility that the object will try to call back into your deallocated object using the delegate design pattern. So if you have something like this in your object.
[_xmlParser setDelegate:self];
you should always have a dealloc method even under ARC to prevent the possibility of a crash in the case where your object gets destroyed while still doing work. It is very common to have your object destroyed while doing work. imagine a UIViewController that shows images from the internet. If you had a FetchImage class that used the delegate design pattern to lookup images that then calls a routine on the object when the lookup finishes, it is easily for the user to pop into and out of your UIViewController while your FetchImage object is still doing work on the background thread. You might not ever notice this when testing, but if you have hundreds of users, some of them will notice because the app will crash when your object tries to call a method on the SELF reference.
If your object uses the delegate design pattern, always have this to cleanup:
#pragma mark - dealloc - cleanup delegate references to prevent callbacks into deallocated objects (EXC_BAD_ACCESS / KERN_INVALID_ADDRESS)
- (void)dealloc
{
[_xmlParser setDelegate:nil];
// for non ARC based code you would also call: [super dealloc];
}
search every class in your project, if you have setDelegate:self or delegate = self then your users are most likely experiencing race condition crashes with your app if you don't have a dealloc cleanup method as described above. If you don't have the dealloc, add it even if you never see crashes when testing. -rrh

App Crashes if AddAnnotations doesn't finish

I have an Application, which is a SplitViewController that has a master view on the left and the detail view on the right. One of the views (Branch Finder) is a Map view that loads a series of Annotations to the Map.
If I let the annotations load before switching to any other view (loading the annotations take takes all of 1 second) then everything is fine. However, if the user quickly switches off the Branch Finder view, whilst the annotations are being loaded, then the App will crash with the following notice:
[BranchFinder_iPad respondsToSelector:]: message sent to deallocated instance 0x807d230
Now, my thoughts are that the deallocated instance would refer to the Array (declared in the header of the view) that contains all the annotations being released and set to nil when the user leaves the BranchFinder_iPad view. This is the array that is being passed to the addAnnotations method.
[self.mapView addAnnotations:branchSites];
Has anyone else encountered an issue where leaving a view, mid-way in the add allocations and a crash occurs if the user moves to another view.
Just to clarify:
If I wait for the annotations to load, switching to any other view causes no problem.
I did have a custom annotation view, but I stripped that out of my code (to eliminate it from the mix). Doing this has not changed anything.
I have looked elsewhere for help on this issue, but a lot of the view tutorials regarding map views are single view only, so this issue hasn't arisen.
I have found a vaguely similar issue # the following: mapkit addAnnotations crashes
And finally, I have just made the jump to x-code 4. I think some of my problems are just because I'm relearning some of the things I should know.
Regards,
Nathan A
PS: I wanted to attach an image to this, but am having trouble. I don't have the reputation points to do it natively, and my workplace doesn't allow me access to any image hosting portals. I will endeavour to add an image later today.
Hey anyone who reads this.
I basically performed a rookie mistake here - for the MKMapView in my application, I had to set the delegate to nil as part of the deallocation routine within my view. THe apple documentation makes mention of this in the below document:
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapViewDelegate_Protocol/MKMapViewDelegate/MKMapViewDelegate.html
For the relevant section:
Before releasing an MKMapView object for which you have set a delegate, remember to set that object’s delegate property to nil. One place you can do this is in the dealloc method where you dispose of the map view.
Not having this was only causing an issue if I switched to another view AND if the MKMapView was still being referenced in executing code, such as the addAnnotations routine.

Writing an own iPad photogallery - dealloc error

i want to write my own photogallery like the original "Photos.app" from apple.
I´ve created a UITabbarcontroller in the AppDelegate and then an "ImageViewController" and a "VideoViewController".
In the "ImageViewController" i´ve added an UIScrollView and then made an instance of my own "PhotoGallery" with different properties like imagePerRow, images, paddings etc.
For the "PhotoGallery" i´ve created a new objective-c class as a subclass of "NSObject", where i´m positioning all the different images as UIButtons.
Then i´ve added another function which describes the arrangement for all the images when the device orientation has changed. And the dealloc-function. Thats all.
This class works great, also the rearrangement when the device orientation has changed. The problem is, if i simulate a memory warning in the ios-simulator, the first time the PhotoGallery gets correctly dealloc but if i simulate a warning again, i get a error-message: "[PhotoGallery release]: message sent to deallocated instance ".
I thought its because of the subclass as NSObject, right?
Then i´ve tested it as a UIView. With the same error. So know i don´t know what to do anymore. Hope you understand what´s the problem and you would give me some hints on that..
Think about calling the init-function again? How? Need "drawRect"? I´ve no idea.
Thanks for your time and help,
G.
You're probably not setting the property which holds a reference to the PhotoGallery to nil.
ie. You're keeping a reference to a deallocated instance, and attempting to call release on it.
bad example:
- (void) didReceiveMemoryWarning
{
[photoGallery release];
}
safe(r) example:
- (void) didReceiveMemoryWarning
{
[photoGallery release];
photoGallery = nil;
// or combine both actions if your property attributes are set up to accommodate it:
// self.photoGallery = nil;
}
In the bad example, photoGallery still holds a reference to a now-deallocated instance, and the second memory warning will attempt to send a message to it.
In the safe(r) example, photoGallery is nil, and sending a message to nil is safe.

Resources