How to get rid of a UISwitch when changing scenes - ios

I am using a UISwitch in in the menu of a Cocos2d game I am making.
After the scene is changed (the user clicks any button and goes to a different scene/layer the switches are still on the screen
I have tried setting switch1 = nil; and switch2 = nil;in my dealloc but that doesn't work. How would I do this?
Edit: Also tried [switch1 release]; which didn't work either

You generally remove controls from a view with:
[switch1 removeFromSuperview];
If you have any strong references to that control elsewhere, you can then do the appropriate memory management to release the switch at that point (e.g. setting it to nil or releasing it, as appropriate). You'd have to tell us about how it's defined (strong or weak, property or ivar, IBOutlet or programmatically created, etc.) for us to provide counsel there, but you probably have that covered.

Related

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?

Why not just declare all #properties as strong and nil them?

An application that I am working on, that uses ARC and needs to support iOS 4.3 and iOS 5, declares every outlet as #property (strong, nonatomic) IBOutlet in the .h file.
e.g.
// myClass.h
#property (strong, nonatomic) IBOutlet UITextView *myTextview;
I know that with ARC only properties which do not hold a strong reference to an object are released.
As a result, the App relies on - (void)viewDidUnload to set the property myTextview to nil.
i.e.
// myClass.m
- (void)viewDidUnload
{
[super viewDidUnload];
self.myTextview = nil;
}
I know, from Apple's Documentation, that Outlets should generally be weak except those from File's Owner ( i.e. A Runtime Object that owns the contents of the iOS Storyboard scene) to Top-Level Objects (my rule of thumb is to use anything that appears in the window with File's Owner, First Responder and View).
Anything I add to the view will be a subview and thus is retained by it's direct superview, meaning a weak reference should be used.
I am also aware that - (void)viewDidUnload is deprecated in iOS 6 and is not called.
1st Question : What are the issues with taking the approach of declaring every outlet as a strong property and setting it to nil in viewDidUnload, apart from the fact that viewDidUnload is deprecated in iOS 6?
My intuition tells me that it is because situations arise where you can set a pointer to nil, before viewDidUnload is called. So you should, to free up memory on the heap. Is there a noticable performance change if this is the case?
2nd Question : Should I go back throughout the project and change strong to weak? Why? Is it worth the time?
3rd Question : If I was to declare the property in a class extension, to 'hide' it, how does this affect my rule of thumb for deciding on when to use strong or weak.
I know there are many threads here that discuss this issue. But many I've found are out of date, and do not address this issue directly. Thanks.
First, a few of your presumptions need addressing:
I know that ARC only releases properties which do not hold a strong
reference to an object. As a result, the App relies on -
(void)viewDidUnload to set the property myTextview to nil.
Not quite. ARC never retained weak properties in the first place. As for strong properties, ARC still releases them, but not until dealloc is called.
viewDidUnload was never used to prevent leaks. It was essentially an optimization, and one that Apple decided was no longer worth the trouble. To understand, consider the standard lifecycle of a pre-iOS6 view controller:
1. Allocated
2a. View Loaded
2b. View Unloaded
3. Deallocated
Where 2a and 2b could be repeated any number of times. For example, a view controller at the bottom of a navigation stack (its view being hidden) could have its view unloaded in low memory situations. It would then be reloaded the next its view became visible.
The method was essentially saying "Hey view controller programmer, we're running low on memory, and nobody can see me anyways, so I'm releasing my view. If you could do the same for your strong properties, that would be great."
That process had subtleties and was generally confusing. As a result of the tediousness, Apple deprecated it. Views are no longer unloaded, so there's no point in implementing it. The key point is that all your strong properties will still be released in ARC's dealloc method.
I know that Outlets should generally be weak...
Why do you know that? There's nothing special about outlets. The 'IBOutlet' keyword is really just for Xcode's benefit when designing things with its visual tools. It has no effect on the compiled code. So, when thinking about strong vs weak outlets, use the same considerations that you do for any other property, namely "do I need this to exists, or am I okay with it disappearing on me?".
What are the issues with taking the approach of
declaring every outlet as a strong property and setting it to nil in
viewDidUnload, apart from the fact that viewDidUnload is deprecated in
iOS 6?
There are no issues with that. If you want your properties to exists as long as your controller, then use strong. viewDidUnload has nothing to do with this. On older iOS versions, you could release strong outlets in viewDidUnload if you want.
Should I go back throughout the project and change
strong to weak? Why? Is it worth the time?
Again, just use whichever qualifier makes sense for your use case. You're almost always safe using strong for you outlets.
If I was to declare the property in a class extension, to 'hide' it,
how does this affect my rule of thumb for deciding on when to use
strong or weak.
There's no difference.
1st question: The outlets are subviews of the main view which is a property of the view controller. If you declare them as weak, they have a retain count of 1, since they are subviews. If the view is released, they are also released. If you declare them as strong, they have a retain count of 2, since they are subviews, and strong properties of the view controller. So they are only released when the view controller is released (which releases also its view and its subviews). To my understanding, the difference is that when the view of a view controller is released, e.g. when it is not presented and memory is low, the outlets still allocate memory when they have been declared as strong.
2nd question: I believe in most circumstances it does not matter.
3rd question: I believe if you declare properties in a class extension, the simply belong to the class, and thus there is no difference in handling them compared to "real" class properties.
My approach would be to make sure not to declare properties as strong that could result in retain cycles, what happens, i.e., if you declare a delegate as strong.

When do I use removeFromSuperview?

I have a small question when programming objects in objective-C. I have an App that is just about complete and everything works fine. My question is that I set my objects to nil and release them at appropriate times.
But is this enough or when and where should I use removefromsuperview?
In the case of adding a UIButton to a UITableViewCell I add the UIButton with the following code:
UIButton *buttonReset = [UIButton buttonWithType:UIButtonTypeContactAdd];
buttonReset.frame = CGRectMake(250.0f, 7.0f, 75.0f, 30.0f);
[cell addSubview:buttonReset];
buttonReset addTarget:self action:#selector(resetSettings) forControlEvents:UIControlEventTouchUpInside];
buttonReset = nil;
[buttonReset release];
Do I also need to use
[buttonReset removeFromSuperview];
in this case?
buttonReset = nil;
[buttonReset release];
This doesn't make sense. You set a pointer to nil (null pointer) and then send a message to it. In most other languages this would result in a crash. In Objective-C it's allowed, but nothing will happen. You have to release before setting to nil. But you shouldn't do neither in this case, because buttonReset is an autoreleased object (you didn't use alloc/init to create it), so you don't own it and therefore you must not release it.
You also don't have to use removeFromSuperview in this case. You add a button (a subview) to your cell (the superview). The superview will hold a strong (retaining) reference of the button. When the cell is then released, it will also handle all of its subviews. You only have to remove it yourself when you actually want to do that, but not for memory management reasons.
If you didn't already know about it, you might want to consider using Automatic Reference Counting (ARC) in the future.
No, you should not call [buttonReset removeFromSuperview];, at least not right away: if you do, the button would disappear from screen (given the name of the method, this should come as no surprise). Moreover, you do not need to set your button to nil.
Calling removeFromSuperview is needed when you need the control to be dropped from the screen. If you also release it, the object representing your control would be destroyed. For example, if you added a button programmatically for a specific task, and have to remove that button once the task has been accomplished, calling removeFromSuperview is appropriate.
Calling removeFromSuperview on a view causes it to be removed from its superview. This will make the targetted view disappear from the screen with all the view it contains.
In your situation, I would just set the object to nil and be done with it.
See does removefromsuperview releases the objects of scrollview?.
There are interesting informations in it.
but it's worth digging deeper into this, because it's a very important
concept in ObjC. You should never call -release on an object you
didn't -retain explicitly or implicitly (by calling one of the Three
Magic Words). You don't call -release in order to deallocate an
object. You call it to release the hold you have put on the object.
Whether scrollview is retaining its subviews is not your business (it
does retain its subviews, but its still not your business). Whether
-removeFromSuperview calls -release is also not your business. That's betweeen the scrollview and its subviews. All that matters is that you
retain objects when you care about them and release them when you stop
caring about them, and let the rest of the system take care of
retaining and releasing what it cares about.
you should use just the
[buttonReset removeFromSuperview];
and then
buttonReset = nil;
as apple saying
If the receiver’s superview is not nil, the superview releases the receiver. If you plan to reuse a view, be sure to retain it before calling this method and release it again later as appropriate.
in UIView Referance

Strange ARC behaviour in non-optimised vs optimized binary

I had a hard to track bug which only appeared in the Release build of my app, but not in the Debug build. The relevant difference between the builds turned out to be that the Debug build was compiled without any compiler optimization, whereas the Release build was compiled with -O (the bug was reproducible on all other optimization settings as well). This is all on LLVM.
In my view controller I have a property self.basicInfoContainerView defined as:
#property (weak, nonatomic) IBOutlet UIView *basicInfoContainerView;
I then removed the subview from one view, and added it onto another.
[self.basicInfoContainerView removeFromSuperview];
[self.infoTextView addSubview:self.basicInfoContainerView];
Depending on the compiler optimization level, different things happened.
With optimization on: as soon as the view was removed from its superview, the view was deallocated and self.basicInfoContainerView was a zero'ed, and as a result was not added as a subview to the new view.
With optimization off: the subview was not immediately deallocated and was successfully added as a subview to the new view.
(When I changed the property storage qualifier to strong, the view survived in both cases, but even though that solved the problem, but that's not really my question.)
I would love someone to help me understand what is really going on here. Why does weak not immediately release my view (and zero the pointer if retain count == 0) when compiler optimization is turned off?
It's really not unusual to see non-optimized code that keeps extra local (and strong) references to objects. So your unoptimized code must have a local strong reference to this 'basicInfoContainerView'. That reference stays in scope through the method, and isn't being released probably until the method returns.
This is really just an accident of sorts that is masking a real bug in your code. The fact of the matter is as soon as you do [self.basicInfoContainerView removeFromSuperview], you can't expect that your basicInfoContainerView will survive, because you don't have any explicit strong reference to that view any more.
The way to fix this, of course, is to create an explicit strong reference to that view. Then you've made your intention clear to the compiler, and you should get the result you want whether the code is optimized or not:
UIView *containerView = self.basicInfoContainerView
// this local variable is that explicit strong reference you need
[containerView removeFromSuperview];
[self.infoTextView addSubview:containerView];
// the compiler can/will release this view when the local variable
// 'containerView' goes out of scope
Hope that helps.

Appropriate way to delete/release a UIView after removeFromSuperview

I'm playing around with drawing in iOS apps. I have a class that is a subclass of UIView that draws some lines and stuff. When the user presses a button, I instantiate the class and do an addSubView on the view of the main UIViewController of the app. The more times the user presses that button, the more instances of that class get added to the view. It's working just fine.
Now I want to provide the user a way to delete one of those views. So far I've put a [self removeViewFromSuperview] into the touchesBegan method of the custom UIView. So when the user presses the drawing it gets removed from the view. But, it's not actually deleted, right? Since the view was instantiated within the method that executes when the button is pressed I have no way to reference it from within the UIViewController. What's the appropriate way to make sure I'm not wasting memory with a UIView that was created and removed?
On a related note, if I was to put a toggle switch on the main window's UIView that toggles delete, how can I check from within touchesBegan if that toggle switch is set to delete=yes? Would I have a some sort of boolean variable in the AppDelegate that I can check from within the UIView subclass? How would I reference that?
Thank you for your help,
Stateful
If you add the view like this:
UIView *viewBeingAdded = [[[UIView alloc] init] autorelease];
[view addSubview:viewBeingAdded];
You can remove it without leaking memory:
[theViewAboutToBeRemoved removeFromSuperview];
Regarding the UISwitch, you don't need to keep its value anywhere unless you need it for something else. You can access its value directly:
if ([theSwitch isOn]) { ... }
You don't even need an IBOutlet, you can access the switch with its tag:
UISwitch *theSwitch = (UISwitch *)[view viewWithTag:<# switch tag number #>];
if ([theSwitch isOn]) { ... }
In this case you must set a unique tag number for the switch in Interface Builder or when you create it.
When you do [mainView addSubView:myView], mainView will retain myView. If you created myView with alloc/init, then you retained it also. If you don't need myView after adding it to the main view then simply do [myView release] after adding it. When you remove it from the main view, it will get released and deallocated.
If you create the UIView with alloc/init, add it to the superview then release the view, the superview will retain it. When it is removed with removeViewFromSuperview it will be dealloc'ed.
I typically autorelease a view after adding it, leaving the parent the only reference.
As to checking a toggle, you could add an IBOutlet so you can inspect it directly. (This may not be pure MVC, but I don't know if putting it in [UIApplication sharedApplication].delegate is necessarily cleaner.)

Resources