Memory question: taking ownership of a subview - iphone

If I have a subview built in Interface Builder, and I want to give it an actual name, I presume the only way to do this is to create a UIView instance variable in my view controller, and then do something like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.moveView=[self.view.subviews objectAtIndex:0];
self.moveView.backgroundColor=[UIColor redColor];
}
In so doing, I can now work with this subview using a conventional name, "moveView," rather than addressing it by its index number within the view heirarchy.
Is this is good way of doing something like this (outside of actually using a custom view class)?
Another way that is perhaps easier and does not require that you figure out the index number seems to be just creating a UIView #property IBOutlet and assigning that to the Interface Builder and doing this:
#property (nonatomic, retain) IBOutlet UIView * sensitivity;
in #interface.
However, I want to know if the "retain" quality of this #property means that my UIView is essentially using up double the memory, since doesn't the Interface Builder UIView also store this in memory? Or will hooking this up in IB make these one and the same, with just a singe actual UIView instance?

Yes, IBOutlets are a much better idea than referencing subviews by their index.
retain doesn't cause a property to copy an object on set—that's what the copy attribute is for—it just increments the object's retain count to "claim" it. I highly recommend reading the iOS Memory Management Guide if you haven't yet. Also note its section on nibs.

Related

Subclass UIViewController or create a custom NSObject when the view is not fullscreen

I need to create a class controller to manage the behavior of a custom view I created.
The standard approach is to subclass UIViewController, but in my case I instead decided to
subclass the NSObject essentially for three reasons:
my view needs to be added as small subview of the main view controller (it will not be displayed using something like presentModalViewController or pushViewController...) and it does not require any kind of toolbar or navigation control inside of it
Most probably my controller will not need to be notified for device orientation because its view will be always used in portrait format, so I'm not interested to receive the usual rotation messages willRotateToInterfaceOrientation etc...
I need to keep this class as lightweight as possible minimizing memory consumption. Not subclassing UIViewController have the advantage to obtain a lighter class without a bunch of methods that I will never need to use
The interface of my controller is pretty simple, example:
#interface MyScrollTabBarController : NSObject <MyTabBarViewDelegate> { }
/**
* The view is created internally by the controller and the client class
* can access to it in readonly mode
*/
#property (nonatomic, readonly) UIView *view;
/**
* A Property to change the view appearance
*/
#property (nonatomic, assign) MyScrollTabBarViewState viewState;
/**
* Others properties used to construct the view's subviews
*/
#property (nonatomic, retain) Location *rootLocation;
#property (nonatomic, readonly, retain) Place *place;
/**
* Designated initializer
*/
- (id)initWithPlace:(Place *)aPlace;
- (void)setRootLocation:(Location *)location animated:(BOOL)animated;
#end
To display its internal view from the parent view controller, I will use something like this:
tabBarController = [[MyScrollTabBarController alloc] initWithPlace:aPlace];
tabBarController.viewState = MyScrollTabBarViewStateXX;
tabBarController.view.frame = CGRectMake(...);
[self.view addSubview:tabBarController.view];
I'd like to know what do you think about my choice, if you think that there could be drawbacks in it and what do you usually do when you need to write a controller for a view which is not fullscreen like mine.
Thanks
Yes, this is the correct approach.
UIViewControllers are specifically for controlling full-screen views, not for sub-screens. In iOS5 there is a mechanism for composing sub-screen viewcontrollers in this way, but that's not available in iOS4 without lots of hackery.
In cases where the view and controller are inherently coupled, you could also consider making a custom view subclass that is its own controller, so for example you could have a self-contained table view subclass that managed its own data and could just be dropped into a page.
I think this is an acceptable solution.
Another solution would be creating a "fat" view that does its controlling itself (like, for instance, MKMapView, UITextView etc.). This might make things a little more manageable, and if the view is very specialized, and its controller is intended to only work with this one class of view, you don't really lose any reusability (because there isn't much).
what do you usually do when you need to write a controller for a view which is not fullscreen like mine
It is not important that your view is not displayed full screen. It is possible (and usual) to have views consisting of subviews which each have their own controller.
I need to keep this class as lightweight as possible minimizing memory consumption. Not subclassing UIViewController have the advantage to obtain a lighter class without a bunch of methods that I will never need to use
Subclassing UIViewController does not consume an unreasonable amount of memory, so this should not be part of the consideration.
[...] if you think that there could be drawbacks in it [...]
With your solution you loose flexibility. It is likely that you will reuse your solution in a context where you need to respond to UILifecyle-Messages or use other UIViewController features.
If your views shall be lightweight you could consider using a UIView subclass and use a delegate for the logic behind your view.
Hi You are subclassing NSObject and declaring a UIView inside it
#interface MyScrollTabBarController : NSObject <MyTabBarViewDelegate> { }
#property (nonatomic, readonly) UIView *view;
I Suggest you should subclass UIView, so you will not have to declare an additional view object.
so instead of self.view you can simply refer as self
tabBarController = [[MyScrollTabBarController alloc] initWithPlace:aPlace];
tabBarController.viewState = MyScrollTabBarViewStateXX;
tabBarController.frame = CGRectMake(...);
[self.view addSubview:tabBarController];

Should every IBOutlet have a property?

We create property for a variable for using it in some other view. Same we do for IBOutlets. But not always for using them. Is it necessary to create property for each IBOutlet we just created it our xib? Or is it only a good practice to do so?
I like to look at it is in terms of ease of memory management, and external access. If you need to access it externally, obviously make a property. (Yes ease of memory management, if it's easy you won't mess it up, if you don't mess it up it doesn't become a bug later)
80% of the time my view controller has the IBOutlets and nobody else accesses them, therefore ivars work.
The problem is that when you don't use #property, the assigned value is still retained. Then you need to remember to release it even though you didn't retain it yourself, which I found counter-intuitive.
For that reason I usually use #property (assign) for the ones I won't be changing, and #property (retain) for everything else, and never declare IBOutlets directly as ivars.
Example:
#interface something : NSObject {
//This one needs to be RELEASED then set to nil in both viewDidUnload, and dealloc.
IBOutlet UILabel * myLabel;
//also cannot be accessed outside of "something" class (technically it can, but don't do that)
//I NEVER declare my outlets this way.
}
//This one can just be set to nil in viewDidUnload and dealloc
#property (nonatomic, retain) UILabel * myOtherLabel;
//it can also be accessed from mySomething.myOtherLabel by any other class.
//This one just works. I don't own it, the view owns it, so I don't retain/release.
#property (nonatomic, assign) UILabel * myOtherOtherLabel;
//It also provides access to outsiders.
//I wouldn't recommend using this type if you want to change the value though.
It is not necessary to create a property for each IBOutlet.
Specifically, if you access the outlet only from the class where it is declared, you do not strictly need the property. If you have a property, you get the advantages that properties offer, but you could always directly refer the outlet directly.
If you plan to access the outlet from another class, then a property is useful so you don't have to define yourself setter and getter methods.
If you want to use the IBOutlet for only the view for which you created the XIB then no need to set the property here. But yes, it is good practice to use but not mandatory to use everytime we create IBOutlet for the view.
If what you are going to display is not going to change, you can skip creating a property or a IBOutlet for that widget.
For example in a screen where you have a label and a textfield and the label always has the string "Name:" and textfield is used for getting input from the user, you have to just create a referencing outlet for the textfield to access the data input from the user. Creating a referencing outlet for label doesn't make any sense here.
I hope you get the point.
Properties are a feature in Objective-C that allow us to automatically generate accessors, and also have some other side benefits. so as Praveen S gave you an example with Label and UIText i just little explore.
Lets say you have nothing to do with UILabel you do not exactly need to set the properites but if are asking from user to give some text to your UITextField you have to set the properties. and if you setting the properties with retain, you must release it in viewDidUnload.
If you want to change the Contents of your display then you should add the property..for an example if we want to change the label text then we need to use IBOutlet nd Property so that we need to able to get to the label control that the framework will build from our nib..

Retain vs Assign for controls inside NIB/XIB using the iPhone SDK

I'm using Interface Builder to build my rootViewController, which is retained by my application delegate. I have a few controls in this XIB such as a couple UIButtons, a UISlider, etc. as IBOutlets, hooked up properly in Interface Builder.
On the code implementation side of the XIB, I've seen some people use:
#interface RootViewController : UIViewController {
IBOutlet UIButton *button1;
IBOutlet UIButton *button2;
...
}
#property(nonatomic, assign) UIButton *button1;
#property(nonatomic, assign) UIButton *button2;
#end
Why do they use assign instead of retain? I've seen some people not even use an assign property.
Is it pointless to use retain since the rootViewController's XIB will always contain a reference to them as long as it is loaded? Or are they just being lazy and not going through the steps to retain, synthesize & dealloc? Seems to me like it can't hurt to keep a reference around as long as the control is needed and the viewController hasn't been dealloc'ed, but just wondering if XIB's do something differently where this wouldn't be necessary.
I've read the memory management guide, btw.
Thanks!
It cant hurt to keep all subviews as assigned instead of retained as long as they stay a child from there superview.
When you remove it from its superview and want to add it as a subview later on in your code. Thats not possible. When you remove it from its super its retain count will probably turn to zero. Thats one of the reasons why you use retain. Your controller object will then always be a owner of the view object.
I cant think of other reasons you must use retain instead of assign.
I always use retain, i think its a best practice for outlets and it seems to be a convention.

Does an IBOutlet needs to be a property & synthesized?

In most examples I see the following setup of IBOutlets:
(Example A)
FooController.h:
#interface FooController : UIViewController {
UILabel *fooLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *fooLabel;
#end
FooController.m:
#implementation FooController
#synthesize fooLabel;
#end
But this works also fine (notice: no property and no synthesize):
(Example B)
FooController.h:
#interface FooController : UIViewController {
IBOutlet UILabel *fooLabel;
}
#end
FooController.m:
#implementation FooController
#end
Are there any downsides of defining IBOutlets as in Example B? Like memory leaks? Seems to work fine and I prefer to not expose the IBOutlets as public properties as they are not used as such, they are only used in the controller implementation. Defining it in three places without a real need does not strike me as very DRY (Don't Repeat Yourself).
On Mac OS X, IBOutlets are connected like this:
Look for a method called set<OutletName>:. If it exists call it.
If no method exists, look for an instance variable named <OutletName>, set it without retaining.
On iPhone OS, IBOutlets are connected like this:
call [object setValue:outletValue forKey:#"<OutletName>"]
The behavior of set value for key is to do something like this:
Look for a method called set<OutletName>:. If it exists call it.
If no method exists, look for an instance variable named <OutletName>, set it and retain it.
If you use a property, you'll fall into the "Look for a method called set<OutletName>:..." case on both platforms. If you just use an instance variable, then you'll have different retain/release behavior on Mac OS X VS iPhone OS. There's nothing wrong with using an instance variable, you just need to deal with this difference in behavior as you switch between platforms.
Here's a link to full documentation on just this topic.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6
On Mac OS X, IBOutlets are not retained by defaults. This is the opposite of the behavior on iPhone OS: on iPhone OS, if you don't declare a property it is retained and you must release this property in the dealloc method. Additionally, the 64-bit runtime can synthesize instance variables using property declarations. That means that someday the instance variables (with the IBOutlet) may be omitted.
For these reasons it is more homogeneous and compatible to create always a property and use the IBOutlet only in the property. Unfortunately, it is also more verbose.
In your first example you always have to release the outlet in the dealloc method. In your second example you must release the outlet only with iPhone OS.
The end result is exactly the same, but you have to keep a few things in mind:
When using instance fields as outlets, you should NOT release them in dealloc.
When using properties that have the (retain) attribute, you have to release the property in dealloc (using self.property=nil or by releasing the backing variable). This makes it a lot more transparent as to what's going on.
Actually it all comes down to the same old rule: "thou shalt release what you alloc/retain". So in case you use an instance field as outlet, you didn't alloc/retain it, so you shouldn't release it.
Its possible that those examples use the retain because the sample code is programmatically allocating and initializing a UILabel and then adding it to the UIView. That's the case for many examples, since learning how to use Interface Builder is often not their point.
The second example (no property and no synthesize) with the IBOutlet is used when the developer 'assigns' the UILabel (Button, View, etc) within the Interface Builder -- by dragging the IBOulet to the Label or other View component. In my opinion, the preceding drag and drop action (Label onto View) also add the subview, the Label to a View -- and so on. Label is retained by a View; a View is retained by Window; Window is retained by File's Owner. File's Owner is usually your Document that is booted up in main.
You will note that when you step through your program (by adding an awakeFromNib
- (void)awakeFromNib
{
[fooLabel blahblah];
}
that fooLabel already has a memory address.
Thats because the Label was initialized from a file bundle (the nib file) using not init but initWithCoder. Which essentially deserializes the filestream to an object - and then sets the IBOutlet variable. (We're still talking about the IBOutlet method).
Also note that the aforementioned iOS method uses the Key Value method
call [object setValue:outletValue forKey:#"<OutletName>"]
which is the Observer/Observable pattern. That pattern require the Observable object reference each Observer in a Set/Array. A change in value will iterate the Set/Array and equally update all Observers. That Set WILL already retain each Observer thus the lack of retain in iOS.
Further and the rest is speculation.
It seems that cases when you do use Interface Builder then
#property (nonatomic, retain) IBOutlet UILabel *fooLabel;
should possibly be changed to
#property (nonatomic, weak) IBOutlet UILabel *fooLabel;
or
#property (nonatomic, assign) IBOutlet UILabel *fooLabel;
And then it needn't be released in a dealloc method. Plus it will satisfy the OSX and iOS requirements.
That's based on logic and I could be missing some pieces here.
Nevertheless, it may not matter if the view is persistent through the life of your program. Whereas a label in a modal dialog box (open, close, open, close) may in fact have over-retained and leak per cycle. And that's because (speculation again) each closed dialog box is serialized into a file system and thus persists x,y position and size, along with its subviews, etc. And subsequently deserialized ... on the next session open (Opposed to say minimiz or hidden.)

How would you implement a dataSource object for an UIScrollView?

Tell me if I am wrong with that:
I made an new class ScrollViewDataSource. That class conforms to an protocol I created within my delegate for the scroll view. Well, it's a very special delegate that does some very complex stuff upon scrolling. So this delegate receives that data source object upon initialization. The datasource object now has a method
(NSArray*)subviewsFromIndex:(NSInteger)fromIndex toIndex:(NSInteger)toIndex;
so when the user scrolls, the delegate rings the datasource object lots of times dunring scrolling to ask for data. I'm going to recycle views during scrolling. That means, if the user scrolls down, I remove the views from the top to the bottom, and fill them up with new data.
The NSArray contains UIView objects, which will be positioned appropriately during scrolling. Also, on first launch of the view that contains the scroll view, the data source will deliver the data to display the first visible contents.
Is that a good pattern, or do you have better ideas for that?
BTW: I know a UITableView does something similar. But I want to learn that. It's a practise for me. Thanks!
May,
This is the best pattern that you can make use of. Exclusively followed by Apple in various of their data displaying views like UITableView in iPhone and NSTableView,NSOutlineView in Mac.
All the best.
If your content views are using same layout, I would make ScrollViewDataSource containing only the data that content views needed, so I don't need to alloc/create new UIView for my UIScrollView when asking new data (since MyScrollView hold the content views that I can reuse):
#interface MyScrollView : UIView {
#private
id <MyScrollViewDelegate> _delegate;
id <MyScrollViewDataSource> _dataSource;
UIScrollView *_scrollView;
NSMutableArray *_contentViews; // you need to create/maintain/reuse contentView from here
}
#property (nonatomic, assign) id <MyScrollViewDelegate> delegate;
#property (nonatomic, assign) id <MyScrollViewDataSource> dataSource;
#end
#protocol MyScrollViewDataSource <NSObject>
#optional
- (NSString *)myScrollView:(MyScrollView *)myScrollView requestTitleForContentViewAtIndex:(NSInteger)index;
- (UIImage *)myScrollView:(MyScrollView *)myScrollView requestLogoForContentViewAtIndex:(NSInteger)index;
#end
...
The good about this is, your MyScrollView interface would look clean to superview, and you are dealing all the scrolling, layout, redraw and content updating stuffs within your MyScrollView AND without bothering other views or controllers from outside.
But, if your content views are totally different to each others, I won't use pattern like this.