UIView frame sent to deallocated instance - iphone

I am currently working on an application that has some ViewController with a button on it that pushes to a UITableViewController with Search Bar and Search Display controller. I have some data in the cells and that gets populated. I have added the following code to hide the search bar and also make it clearcolor when you do see it:
[[self.searchBar.subviews objectAtIndex:0] removeFromSuperView];
[self.searchBar setBackgroundColor:[UIColor clearColor]];
CGRect newBounds = [[self tableView]bounds];
newBounds.origin.y = newBounds.origin.y + searchBar.bounds.size.height;
[[self tableView] setBounds:newBounds];
Now this works when I am using the iOS simulator, but when I run it on my device and begin to scroll, either up or down, it crashes and gives me the following error:
EXC_BREAKPOINT (code = EXC_ARM_BREAKPOINT, subcode = 0xdefe)
I then enabled Zombie Objects to further debug and got this:
-[UIView frame]: message sent to deallocated instance 0x156b1430
When I take off:
[[self.searchBar.subviews objectAtIndex:0] removeFromSuperView];
[self.searchBar setBackgroundColor:[UIColor clearColor]];
and run my application on my device again, it does not crash and works fine.
Anyone have any ideas whats going on and how this is happening? Thanks in advance!

[[self.searchBar.subviews objectAtIndex:0] removeFromSuperView];
//This Line remove search bar from view ,which means it is deallocated at that moment so when you again try to remove it ,,the app crash ..
// So,instead of this try to hide searchbar ,,
Self. searchBar.hidden =YES;

I think UISearchBar has unsafeunretained reference of [self.searchBar.subviews objectAtIndex:0];
And You set the Bounds of UITableView then change frame of UITableView.
It would fire auto resizing and layoutSubviews.
So, UISearchBar's layoutSubviews method access [self.searchBar.subviews objectAtIndex:0].frame
for layout or auto resizing.
It's not recommended that change view in UIControls from SDK.
There is an idea that Setting hidden=YES instead removeFromSuperview.

I was having this same problem. Got to this page, read the words 'zombie objects' in the question and remembered that I'd left zombie objects enabled. After disabling them, the problem went away. Now when I scroll my tableView, there's no crash.
This may be weird, but perhaps it will help someone...

Related

SLComposeViewController Views sent to back in app and becomes unresponsive

I have a button in my app to bring up an SLComposeViewController for use with Twitter. When the view is presented it animates in correctly and the disappears. I have found that when it disappears it is sent to the back of the current view and I have no way to bring it back. I have tried manually sending all the views on top to the back in code with no luck. I feel there is something fundamentally wrong with my app for this to happen as this behaviour is seen at any level to the Navigation Controller in the app. Below is a screenshot of the SLComposeViewController being the Navigation Bar in the app, I made the ViewController's view have an Alpha value of 0.0f to illustrate my point:
I really don't know what is going on here and any help will be greatly appreciated. The code I am using to present the SLComposeViewController is pretty standard and I have tested it in another app and works fine:
NSString *message = [NSString stringWithFormat:#"#%#", [twitterInfo objectForKey:#"hashtag"]];
if ([appDelegate isSocialAvailable]) {
// code to tweet with SLComposeViewController
SLComposeViewController *twitter = [[SLComposeViewController alloc] init];
twitter = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[twitter setInitialText:[NSString stringWithFormat: #"%#", message]];
[self presentViewController:twitter animated:YES completion:nil];
}
Thanks for posting this, I had the same thing happen because I was adding a CAShapeLayer to my window for a gradient effect. Your post helped me figure out that this was the problem.
It looks like this is happening is because they are adding their view's layer to the window's sublayers--at index 0 I might add! This is contrary to what you would expect, which is that they would add their view as a subview to the presenting view controller's view.
They must have just thought that people don't add layers to their window and they want to make sure they are not competing with your view stack. Why they would put it into index 0 must only be because someone is in the habit of doing -[CALayer insertLayer:layer atIndex:0] I suppose.
I'm not certain but I am guessing this could be the case with any modal view controller.
The fix is pretty simple:
[viewController presentViewController:facebookViewController
animated:YES
completion:^{
facebookViewController.view.layer.zPosition = 1000;
}];
After a week of tearing my hair out to find a solution to this I have found the offending code in the app, a little trick to round the corners of the whole app, well make it seem like the corners are rounded by adding an image there:
UIImage *bottomOverlayImage = [UIImage imageNamed:#"bottom_overlay.png"];
CALayer *bottomOverlay = [CALayer layer];
bottomOverlay.frame = CGRectMake(0, self.window.frame.size.height - 9, bottomOverlayImage.size.width, bottomOverlayImage.size.height);
bottomOverlay.contents = (id)bottomOverlayImage.CGImage;
bottomOverlay.zPosition = 1;
[self.window.layer addSublayer:bottomOverlay];
If anybody could tell me why this code would mess up the Twitter View that would be really helpful for future reference. This code was placed in the app delegate and run on first load.

iOS subview size not correct when changing orientation

I got an app will do auto login for users. When logging in to the server, there will be a 50% transparent view with "logging in..." message showing and it blocked user from doing anything else(Please don't argue with me whether I should do that by HIG, we gotta let the user login in order to do anything). So what i did was create a xib LoadingMessageViewController in IB, and in the main view controller's - (void)viewDidLoad(), I initialize the view controller and do [self.view addSubview:LoadingMessageViewController.view];
It will work fine in portrait mode, but not in landscape. I saw tons of posts about this problem and nothing really worked for me.
I set autoresizingMask to true, set autosizing in IB, I also tried to use [[[window subviews] objectAtIndex:0] addSubview:LoadingMessageViewController.view] instead of [self.view addSubview:LoadingMessageViewController.view]. The problem with using [[window subviews] objectAtIndex:0] is it happen in -(void)ViewDidLoad, and at that point, the view has not really finished loading to the screen yet, and subviews at that point is nil, and call objectAtIndex will cause a pointer out of range exception.
Please point me to the right direction.
Thanks for reading my post.
This is how it looks like:

CATransform3D weird UIScrollView contentOffset

I'm doing a cool CA3DTransform while a UIScrollview is scrolling in the scrollViewDidScroll delegate method. It works perfectly when you use your finger to scroll, so when scrolling manually everything is perfect.
But, when I set scrollview contentoffset programmatically like:
[scrollView setContentOffSet:CGPointMake(0,460) animated:YES];
It still calls the delegate method scrollviewdidscroll, so the same animation methods are called, so I still see the correct animation, BUT, somehow parts of the view are missing during and after the animation! I've tried to set the layer.zPosition on all things and it doesn't seem to help. It should be fine since manually scrolling does work without parts of views going missing... Somehow calling this method programmatically differs and I have no idea why!
Post your question in this way is not very clear, considering that with the delegate scrollViewDidScroll, I can print me the code, either manually or programmatically.
...
UIScrollView *sv = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 10, 320, 200)];
[sv setContentSize:CGSizeMake(640, 200)];
sv.delegate = self;
[sv setContentOffset:CGPointMake(320, 0) animated:YES];
[self.view addSubview:sv];
...
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(#"---%#---", NSStringFromCGPoint(scrollView.contentOffset));
}
In this simple example, you can see that the delegate actually works.
Excuse the simplicity of the answer, but the only question you ask is hard to give you help.
I had a similar problem (in the context of using a scrollview for a slideshow) but solved it by using scrollRectToVisible:NO (NO for no animations), and wrapped that inside a UIView animation block where I also put my animation code.

UIButton, created by Interface Builder, is crashing

I have narrowed down an ugly bug, but since it seems like something internal to the nib/Interface Builder, I'm at a loss of what to do next.
I've got a UIView created in IB which functions as a custom dialog box. It shows a message and two buttons. (Proceed or Cancel.) Both buttons have a Background image set in Interface Builder.
Something is wrong with the way the background image for the cancel button is being handled. With NSZombieEnabled, I've been running the program. Most often, the method below logs this:
-[ModalDialog showInView:title:message:cancelText:proceedText:]
dialogProceedButton <UIButton: 0x7031f10; frame = (286 192; 90 31) // (etc.)
dialogProceedButtonBackground <UIImage: 0x3b36120>
dialogCancelButton <UIButton: 0x3b39cd0; frame = (104 192; 90 31) // (etc.)
dialogCancelButtonBackground <UIImage: 0x3b3a920>
That's completely normal. However, sometimes it does this (I can get this to repeat somewhat reliably if I "rush" the UI by rapid tapping some interface buttons):
-[ModalDialog showInView:title:message:cancelText:proceedText:]
dialogProceedButton <UIButton: 0x7031f10; frame = (286 192; 90 31) // (etc.)
dialogProceedButtonBackground <UIImage: 0x3b36120>
dialogCancelButton <UIButton: 0x3b39cd0; frame = (104 192; 90 31) // (etc.)
*** -[UIImage retain]: message sent to deallocated instance 0x3b3a920
As you can see, NSZombieEnabled found that the background image for the Cancel button has been deallocated, but is being sent a retain message. (Not by me, though... that image is only used for this one button, and only accessed in Interface Builder. I don't have any IBOutlets or any variables linked to that image.)
So, um, what now?
EDIT:
Sometimes, it's not a retain message that gets caught as a zombie, sometimes it's isKindOfClass:
//(the object address is always dialogCancelButton.currentBackgroundImage)
-[UIImage isKindOfClass:]: message sent to deallocated instance 0x1661f0
//occasionally, these come along, too:
*** NSInvocation: warning: object 0x7e0d0b0 of class '_NSZombie_UIImage' does not implement methodSignatureForSelector: -- trouble ahead
*** NSInvocation: warning: object 0x7e0d0b0 of class '_NSZombie_UIImage' does not implement doesNotRecognizeSelector: -- abort
This is my custom UIViews "showInView" method:
- (void)showInView:superView
title:(NSString*)title
message:(NSString*)message
cancelText:(NSString*)cancelText
proceedText:(NSString*)proceedText {
NSLog(#"%s",__PRETTY_FUNCTION__);
NSLog(#"dialogProceedButton %#", dialogProceedButton);
NSLog(#"dialogProceedButtonBackground %#", dialogProceedButton.currentBackgroundImage);
NSLog(#"dialogCancelButton %#", dialogCancelButton);
NSLog(#"dialogCancelButtonBackground %#", dialogCancelButton.currentBackgroundImage);
CGRect rect;
dialogTitle.text = title;
dialogMessage.text = message;
[dialogProceedButton setTitle:proceedText forState:UIControlStateNormal];
if (cancelText == #"") { // SINGLE BUTTON DIALOG
dialogCancelButton.hidden = YES;
rect = [dialogProceedButton frame];
rect.origin.x = 195; //center the button
[dialogProceedButton setFrame:rect];
} else {
[dialogCancelButton setTitle:cancelText forState:UIControlStateNormal];
dialogCancelButton.hidden = NO;
rect = [dialogProceedButton frame];
rect.origin.x = 286; //button on right of dialog box
[dialogProceedButton setFrame:rect];
}
[UIView beginAnimations:#"modalAppears" context:nil];
[UIView setAnimationDuration:0.5];
[superView addSubview:self];
self.alpha = 1.0;
[UIView commitAnimations];
}
Thanks!
Ok, this one's a what-the-heck. I decided to try reversing the images for the Proceed and Cancel buttons. The result was now that the Proceed button image would cause the crash (just as intermittently). I completely deleted the image from my project and from Interface Builder. I then added a fresh copy with a new name and hooked it up.
With the previous setup, I had been able to reproduce the crash about 40% of the time. I've tried about 20 times to reproduce the crash after these changes, and I cannot reproduce it at all now.
If the image or the nib was corrupted, why, why, why would it cause a random/intermittent symptom?
Whattathing. Hope it's well and truly fixed.
Update:
And... so there is a bit more to it. Turns out I discovered that I had coincidentally been using the same image as a placeholder in my (incomplete) instructions view. For temporary convenience there, I was using [UIImage imageNamed:] to grab the image. It was being properly allocated and released, but it seems that IB's cooperation with the imageNamed: method and/or cache is not perfect.
The fact that when I went and grabbed a fresh copy of the image, I also gave it a new name, meant that now the IB button image and the temporary placeholder image were no longer the same image at all.
I went back to a backup of my project from a couple days ago to test my theory. All I did was tell the instructions view to use a different placeholder image. Crashes stopped.
This is probably an SDK bug, then. There shouldn't be any reason not to use an image in IB and also use the same image elsewhere using imageNamed:. If I feel wily or bored one of these days, maybe I'll distill this down into an example project to send to Apple radar.
How is your XIB file wired to your view? What IBOutlets do you have defined? I really doubt you have solved your problem in the way you describe.

iPhone OS: Tap status bar to scroll to top doesn't work after remove/add back

Using this method to hide the status bar:
[[UIApplication sharedApplication] setStatusBarHidden:YES animated:YES];
When setting "hidden" back to NO, the tap-to-scroll-to-top (in UIWebView, UITableView, whatever) doesn't work any more, and requires a restart of the app to get the functionality back.
Is this a bug (I filed a rdar anyhow) or have I missed a step? Should I perhaps expect this behavior since the statusBar "loses touch" somehow with the respective view?
You could try setting the ScrollsToTop property to true again after re-showing it:
[currentView setScrollsToTop:YES];
If that's not working, are you definitely only showing one view? If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored...
In iOS 5.0 you can access the scrollview property of the UIWebView
webView.scrollView.scrollsToTop = YES;
The following fix by Alex worked for me. Thanks!
((UIScrollView *)[[webView subviews] objectAtIndex:0]).scrollsToTop = NO;
Being in a hurry this fix worked great, however given more time I might've subclassed the UIWebView and accessed the protected UIScrollView member directly.
The worry I have with Alex' method is that it assumes that UIScrollView is at index zero of the subviews (encapsulation allows private members to change). Which suggests another solution still:
for (UIView* v in [webView subviews])
{
if ([v isKindOfClass:[UIScrollView class]])
{
(UIScrollView *)v.scrollsToTop = NO;
}
}
I was having a similar problem where the scroll-to-top functionality was lost. Turns out this will only work when you have only one active view at a time (within the same scroll view). In my case I had a table view and another view which would fade in/out. Adding a removeFromSuperview at the end of the animation did the trick.
The answer was in the UIScrollView.h file comments:
/*
this is for the scroll to top gesture. by default, a single scroll visible scroll view with this flag set will get the call. if there is more than one visible with this
flag set or the delegeat method returns NO, the view isn't scrolled
*/
#property(nonatomic) BOOL scrollsToTop; // default is YES. if set, special gesture will scroll to top of view after consulting delegate
You can use the following code to have the UIWebView ignore scrollToTop without the extra UIScrollView:
((UIScrollView *)[[webView valueForKey:#"_internal"] valueForKey:#"scroller"]).scrollsToTop = NO;
I had a similar problem after playing a Youtube video within my app. scrollsToTop was still set to YES but tapping the status bar had no effect.
I finally realised that my app window was no longer the key window. After adding the following line to a UIWindow subclass (which I already had for other reasons) everything worked as it should again:
if (![self isKeyWindow]) [self makeKeyWindow];
I just ran across a similar behavior in the app I'm currently working on. In its case, if you load a YouTube video from within a UIWebView, scroll to top stops working for the rest of the application's life cycle. I kind of assume this might happen after loading the movie player as well, but haven't confirmed. That functionality has been around a lot longer and probably has fewer bugs.
When there are multiple scrollview, you can also set scrollUpToTop to NO for the others scrollview. cf:
setScrollsToTop with multiple UIScrollView classes and/or subclasses(UITableView)
I want to add my case, I add an UIWebView on an UIScrollView, as h4xxr had answered on the top:
If there is more than one scrolling view a scrollViewDidScrollToTop message is ignored
So, I get a simply way to make it work on webView: just set the scrollView·s scrollsToTop property false.
And when tap the status bar, it won`t got intercepted by the scrollView, and the webView scrolls to the top!
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.frame = self.view.bounds;
scrollView.scrollsToTop = false; //igore scrollView`s scrollsToTop
[self.view addSubview:scrollView];
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = scrollView.bounds;
[scrollView addSubview:webView];