I get one problem is that,
This's showads function.
[self.mMainView addSubview:adViewController.view];
//...(my function to display ads)
This's hideads function.
//...(my function to hide ads)
[[AdViewController sharedAdViewController].view removeFromSuperview];
[self.mMainView setNeedsDisplay];
The mMainView is a UIView.
The AdViewController is a UIViewController.
The problems is that after calling showads fucntion, the my ads display on mMainView. But after calling hideads function, the my ads don't disappear, it still appear on mMainView.
Note: After calling hideads and make an interrupt then resume the app, the my ads will disappear.
So, i want to remove it, could you please explain a bit in more detail and show me how to fix it if you can pls ?
You don't need to call setNeedsDisplay when removing or adding subviews. The fact that it updates after an interrupt makes me suspect that you're not calling [[AdViewController sharedAdViewController].view removeFromSuperview]; on the main thread. What is the context of that code?
If it's not on the main thread, you can schedule on it:
dispatch_async(dispatch_get_main_queue(), ^{
[[AdViewController sharedAdViewController].view removeFromSuperview];
});
My app didn't have any crash until iOS 7.1 came out. Now on any removeFromSuperview method, crash. For example: I got view controllers, and when I want to remove a view controller, I remove all of its subviews, and then remove from the stack (stack: I'm storing view controllers in this, for load new contents, and load previous contents):
for (UIView *subView in [contentVc subviews])
[subView removeFromSuperview];
And I got
-[CALayer retain]: message sent to deallocated instance
message
[actual removeFromParentViewController];
is a good way to remove it? And will it release the whole view controller and its subviews? Because instead of removeFromSuperview, my app doesn't crash. I don't understand what have been changed in iOS 7.1.
And how can I remove all subviews in a viewController without removeFromSuperview, and without remove my ViewController (if I just want to add new subviews, and remove the currently content)?
UPDATE:
sometimes crash for:
[myactualviewcontroller.view removeFromSuperview];
-[CALayer retain]: message sent to deallocated instance
Why???
and sometimes if I try to remove the main subview from the view controller view, its got the same crash:
[mainView removeFromSuperview] ( mainView is a single UIView, added to the vc.view )
UPDATE2: (well detailed)
so, I've got a container view. I'm adding a UIViewController.view to this container. And I'm adding a view as a subview to UIViewController.view. This view is not a local uiview, I mean, its declared as implementation{ UIView* mainView } .When my UIViewController will be deallocate, in its - (void) dealloc { [mainView removeFromSuperview]; [mainView release] [super dealloc];}
At the mainView removeFromSuperview my app crash.
It's usually not a good idea to modify an array while you're fast enumerating it. You appear to be using fast enumeration on a a view's array of subviews, and to be modifying that array at the same time (by removing subviews as you go). You could try something like this:
NSArray *subviewsCopy = [[contentVc subviews] copy];
for (UIView *subview in subviewsCopy) {
[subview removeFromSuperview];
}
However, as some others have mentioned, it's a little odd that you need to go to the trouble of removing these subviews manually. Under normal circumstances a view controller's view (and the view hierarchy under it) will be cleaned up automatically when the view controller itself is deallocated.
There are also some good tools available that can help you track down the source of the issue. In particular, you should profile your app (in Xcode, under the Product menu) and choose the Zombies tool when Instruments prompts you. With Zombies you can see the retain/release history of an object that was messaged after it was deallocated.
If you're attempting this manual cleanup of the view hierarchy because you suspect that your views will be leaked otherwise, I suggest that you also try the Leaks tool in Instruments and verify that when this code is disabled the relevant views are actually leaked.
Your program is crashing because you are releasing something more than once. That part is obvious.
The first step in finding it is to enable zombie detection in the debugger. (Project->Schemes->Edit Scheme->Diagnostics->Enable Zombie Objects). The goal here is to make your program crash sooner. This will drop you into the debugger as soon as you try to access a deallocated instance. Sometimes this will point you in the right direction, sometimes not, but it's always better to detect it as close to where the problem is as possible.
The next step is to use the Zombies instrument. This tool will give you more information than the previous step, but it's more complex to use (which is why I made it step 2 instead of step 1). The Zombies tool will keep track of all your allocations and releases, and detect when you try to access a zombie object.
The last resort is to start commenting out code. First comment out everything your program does between the time you create the view controller (the one that crashes) and when you release it. Then run the program and do whatever you need to do to make it display the bad view controller. It won't do anything, obviously, because it's just an empty view controller now, but it should not crash). Then start uncommenting blocks of code, a little bit at a time, and keep running it in between each iteration. This is a repetitive process, and can be tedious if your view controller code is large and complex. But the idea is to keep adding your code back in little by little until you add something back and it crashes - then you know you've found the piece of code that's causing the problem. You have to be creative here and choose carefully how you put your code back in - if your program has a nice modular design, you should be able to do this without much trouble. Spaghetti code will be difficult to do this with, but it might give you a good opportunity to restructure your code while you're at it. By going through this process, you'll narrow down the problem and eventually find the bug by process of elimination.
UPDATED
try to do this:
NSArray *subviews = [NSArray arrayWithArray:[contentVc subviews]];
for (UIView *subView in subviews)
[subView removeFromSuperview];
I think that you got the crash beacuse you're trying to fast enumerate an array that has variable length (in fact when you remove a subview, it is removed also from subview array).
If you want to remove the viewcontroller, just call:
[contentVc.view removeFromSuperView];
[contentVc removeFromParentViewController];
sometimes crash for:
[myactualviewcontroller.view removeFromSuperview];
You shouldn't add or remove a controllers' view from a view hierarchy manually but rather rely in UIWindow's rootViewController, push your controller to a UINavigationController, etc., to get the system to add the view to private underlying superviews. Unless your creating a Custom Container View Controller, which I guess you aren't.
If you just want to handle views manually don't use view controllers as they won't get retained by the system and they won't get any rotation messages, etc. So using a view controller is pointless in that case anyway.
As for subview memory handling, subviews are retained by their superview, so as long as you don't keep a strong reference, you don't need to release subviews, just remove a common superview.
Again, if you properly use view controllers just releasing the controller will get rid of all views.
Finally, you should start using ARC.
1.According to the Apple's documentation, calling removeFromSuperview will remove that view from superview and release it automatically.
So if you are using removeFromSuperview, then you should not call the [removedView release], which will crash your App.
Refer this screenshot from Apple.
In your dealloc implementation, you are having like so
- (void) dealloc {
// Removed from Parent view and released.
[mainView removeFromSuperview];
// no mainView exists in memory , so it crashed the App.
[mainView release];// Comment this line to avoid the crash
[super dealloc];
}
2.You should not mute the container that are being enumerated.
You are having like this,
for (UIView *subView in [contentVc subviews])
[subView removeFromSuperview];
Instead you can implement the same effect by having this one line from Apple.
[[contentVc subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
Please be sure that all of possible delegates removed before views deletion (i.e. someScrollViewDelegate = nil; before [someScrollView removeFromSuperview];) an/or animations are fully completed (all of CATransaction, [UIViev beginAnimation...], [UIView animateWithDuration...] etc.).
please do the following:
1- debug the for (UIView *subView in [contentVc subviews]) and check how many times it iterate.
if it doesn't crash in the first hit you can add this line before you remove the view
if (subView.superView != nil)
else try to make sure that you are not releasing the views twice somewhere else as it's
keep showing and will not crash till you remove it from it's superview.
UPDATE2:
i will consider that you are will aware of memory leaks, and that you have good experience in it.
whenever you add a subview to a view, this will retain the object by 1 in addition to the original 1, that will equal 2, then directly after adding the subview you have to release it, which will decrement the retain count back to one. here is the trick: you don't have to release the subview or remove it from it's parent view to get rid of the remaining retain count. you can simply remove or release the parent view. get the NSMutableArray As an example.
remove the [mainView removeFromSuperview]; from the dealloc: method. you can add it else where like viewWillDisappear: method. dealloc method shouldn't contain anything other than the release calls.
Instead of:
for (UIView *subView in subviews)
[subView removeFromSuperview];
Try:
[subviews makeObjectsPerformSelector:#selector(#"removeFromSuperview");
Try checking if the view is != nil first before removeFromSuperview
example:
#IBOutlet weak var btnSNSApple: UIView!
if self.btnSNSApple != nil {
self.btnSNSApple.removeFromSuperview()
}
I have encountered a delay/pause that I was not expecting and the reason so far has me scratching my head. I have a simple game setup where the UIViewController shows a number of UIButtons [PLAY GAME] [VIEW SCORES] etc. which in turn present a different SKScene
My problem is that when I try and set the visibility of these buttons to visible (perviously set to hidden in viewDidLoad) from the UIViewController they take about 5 seconds to actually show.
#implementation ViewController
- (void)presentTitleScene {
// SHOW BUTTONS
[[self logoLabel] setHidden:NO];
[[self gameButton] setHidden:NO];
[[self scoreButton] setHidden:NO];
[[self creditsButton] setHidden:NO];
// PRESENT SCENE
SKScene *titleScene = [TitleScene sceneWithSize:[[self spriteKitView] bounds].size];
[titleScene setName:#"TITLE_SCENE"];
[titleScene setScaleMode:SKSceneScaleModeAspectFill];
[(SKView *)[self view] presentScene:titleScene];
[self setCurrentScene:titleScene];
}
#end
What happens is all the code runs, the SKScene presents correctly, then after about 5-6 seconds the buttons appear? Is there anything I can do about this (force an update) or is it just a case of design it out or live with it?
This happens on both the simulator and the device.
EDIT:
Looking at the output log you can clearly see that after calling preloadTextureAtlases:withCompletionHandler: that execution jumps to another thread. The method preloadTextureAtlases:withCompletionHandler: is called on the main thread and its supposed to preload the textureAtlas(s) on a background thread, but I was under the impression that the completionHandler would call back onto the main thread, is this assumption right or am I wrong?
EDIT_002:
Moved to answer below.
With regards to preloadTextureAtlases:withCompletionHandler: the completionHandler gets called on a background thread, I would assume the same one that was used to preload the atlases. The problem that I was having was that I was using the completion handler to send an NSNotification to my viewController saying "the assets have loaded, start the game" The issue with this is that "Notifications are delivered in the same thread that they are sent from" so my game also started in the background thread. As a consequence the code that set the UIButtons to visible was also running on that same background thread, hence the delay in them reacting to either being made visible or hidden.
After having spent the whole day looking for a solution I feel only more confused and upset.
Let's face the problem:
I'm developing a single view iOS app made up of an AppDelegate (of course..), A ViewController and a "DrawingClass" (subclass of UIView).
In the main.storyboard i can see my mainViewControllerScene, and inside this main view directed by the viewController, I have inserted a UIView object from the palette in the interface builder and set it to be controlled by my "Drawing class" because I need to use the DrawRect method to draw custom lines.
Well, when starting the app, the defaults lines in my "DrawingClass" are being drawn, so drawrect is being called.
But when, after having pressed a button linked to an IBAction, I try
to call again drawrect through setNeedsDisplay or anything it doesn't
work.
Let's be more clear:
-I'm sure that the view controlled by "DrawingClass" is being drawn correctly on startup
-I'm sure that the IBAction is called (I used an NSLog)
-I can't figure out how to redraw that view. (The one controlled by "DrawingClass")
In the viewController I tried both [self.view setNeedsDisplay] and [myView setNeedDisplay] but none of them called my drawrect method in the "DrawingClass"
What I'm doing wrong? Am I forgetting to init something ? I tried even to call those methods on the main thread but nothing.
I think this question could help many so please ask if you need something more to work out this problem.
Thank you so much.
I am trying to update a UIProgressView progress bar that I have in a UIView during a long resource loading process. Let's say I'm loading a bunch of bitmaps from a NIB file (like maybe a hundred). After I load 10, I issue a .progress to the UIProgressView that is part of a UIView that is already being displayed. So, I issue:
myView.myProgressView.progress=0.2;
Then, I load another 10 bitmaps, and issue:
myView.myProgressView.progress=0.4;
etc., etc. When the app runs, the progress bar doesn't advance. It simply stays at its initial position. At the risk of sounding like a complete moron, do I have to load my resources on a separate thread so the OS can update the UI, or, is there an easier way? Thanks for any assistance.
Yes. Load them on a separate thread. Or just use something like performSelector:
[self performSelector:#selector(setProgressBar) withObject:nil afterDelay:0.0];
(and create a setProgressBar function which reads the current value from a member variable and updates the UI)
You could run a step of the runloop after each update of the UI:
SInt32 result;
do {
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE);
} while(result == kCFRunLoopRunHandledSource);
It could have other bad consequences (for example, enable user to interact with the UI, execute delegates of view controller such as viewDidAppear before they should be executed, etc) so be very, very careful.