creating an object and setting a retaining property - objective-c

How should I set a retained property when creating an object using alloc and init? (Without using autorelease)
With this line in the header (and the corresponding #synthesize line in the implementation):
#property(retain)UIWebView *webView;
These are the three options I have (I think):
UIWebView *tempWebView = [[UIWebView alloc] init];
[tempWebView setDelegate:self];
tempWebView.hidden = YES;
self.webView = tempWebView;
[tempWebView release];
(This one seems the best concerning memory management but it's more lines of code and involves a stupid variable name, so a decrease in readability)
self.webView = [[UIWebView alloc] init];
[self.webView release];
[self.webView setDelegate:self];
self.webView.hidden = YES;
(This one it's more obvious whats happening but the memory management doesn't seem that great, also Xcode's Analyser doesn't like it)
webView = [[UIWebView alloc] init];
[self.webView setDelegate:self];
self.webView.hidden = YES;
(This one is the shortest, it's more obvious than the first example whats happening. But it bypasses the setter, so should a custom implementation of the setter be implemented later it won't work in this case)
So which example should be used, or is there a better way?

The best option, IMO, is the one you don't like, i.e. using autorelease:
self.webView = [[[UIWebView alloc] init] autorelease];
If you do not want to and want a one-liner initialization, the only option is your third one:
webView = [[UIWebView alloc] init];
since all the others requires an explicit line to do an extra release.
I don't see it as bad, especially when it belongs to the init method and you don't reassign it elsewhere without using the property, and I myself use it when it seems reasonable to me.
What works really well with retained properties are convenience constructors like:
self.image = [UIImage imageWithContentsOfFile:xxxxxxx];
So, possibly if you really find that none of the options you listed is fine with you, you might add a category to UIWebView and a convenience constructor doing the autorelease job for you:
self.webView = [UIWebView webViewWith......];

Related

Objective-C: Image Management between classes

I am trying to create a model with multiple images in a factory model style. I have one class that handles the individuals, one class that handles the group of individuals and a ViewController.
testImage = [[UIImageView alloc] initWithFrame:CGRectMake(250, 500, 30, 30)];
testImage.image = [UIImage imageNamed:#"myImage.png"];
testImage.animationDuration = 1.5;
testImage.contentMode = UIViewContentModeCenter;
[self.view addSubview:testImage];
http://jcdeveloperworld.blogspot.com/2009/07/iphone-game-tutorial-part-1.html -- Thanks
That code works when it is just in the viewController, and now I am trying to make the individuals keep track of their own image. So i put the
testImage = [[UIImageView alloc] initWithFrame:CGRectMake(250, 500, 30, 30)];
testImage.image = [UIImage imageNamed:#"myImage.png"];
testImage.animationDuration = 1.5;
testImage.contentMode = UIViewContentModeCenter;
[self.view addSubview:testImage];
in a separate class and then tried to display it from my viewController. It is my understanding that I can't just tell the viewController to display something from a separate class.
flock *newFlock = [[flock alloc] init];
[newFlock makeFlock];
NSMutableArray *tempFlock = [[NSMutableArray alloc] init];
tempFlock = newFlock.theFlock;
individualsClass *tempIndividual = [[individualsClass alloc] init];
tempIndividual = [tempFlock objectAtIndex:0];
UIImageView *tempImage = [[UIImageView alloc] initWithFrame:CGRectMake(250, 500, 30, 30)];
tempImage = tempIndividual.individualImage;
[self.view addSubview:tempImage];
I also tried it without all the copying, but the dot notation started to get in the way because I'm accessing properties of objects in an NSMutableArray (which seems absurdly difficult in objective C). I could use some help in figuring that out too
ie.
flock.[theFlock.individualImage.image objectAtIndex:1] //Doesn't work
I am kind of new to objective C, so perhaps I'm attacking this problem wrong. This is being done for an iPad app
It's not clear what you're trying to do, but you're definitely doing a lot of stuff you don't need to. Consider these lines of your code:
NSMutableArray *tempFlock = [[NSMutableArray alloc] init];
tempFlock = newFlock.theFlock;
The first line declares a variable named tempFlock of type NSMutableArray *. Then it creates and initializes an empty NSMutableArray and assigns it to tempFlock. The second line then assigns newFlock.theFlock to tempFlock, overwriting the only reference to the array you created in the first line. You can just say this:
NSMutableArray *tempFlock = newFlock.theFlock;
Anyway, the correct syntax for your last block is this:
[flock.theFlock objectAtIndex:1].individualImage.image
So maybe this is what you want to do:
[self.view addSubview:[flock.theFlock objectAtIndex:1].individualImage];
Also, flock and individualsClass are not good class names in Objective-C. Flock and Individual might be better names.
And it's confusing that flock instances have a property named theFlock. It looks like theFlock is just an array of individuals, so a better name for the property would probably be individuals.
If all the "dot" syntax is causing problems with understanding just don't use them, they are just an alternate syntax for method invocation.
[myInstance value] is the same as myInstance.value, which can be viewed as a simple substitution.
Also avoiding long compound statements can help understanding, instead use one or more intermediate well named variables. Trust the compiler to optimize them.
So, as #rob writes:
[flock.theFlock objectAtIndex:1].individualImage.image
the equivalent could be:
[[[[flock theFlock] objectAtIndex:1] individualImage] image]
Broken into multiple statements:
tempFlock = [[flock theFlock] objectAtIndex:1];
tempIndividual = [tempFlock individualImage];
image = [tempIndividual image];

Objective C initWithNibName

I am facing some difficulties figuring out what this function in the Apple tutorials stands for:
[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]]
My questions are: what does the "#" stand for before MyViewController?
Addionally, as I am following this tutorial, I was wondering: There are to nibs in my project: the automatically generated MainWindow.xib and MyViewController.xib – I was wondering: why do I have two if I only need one?
Thanks in advance!
The #-sign before a string literal means that the string is an instance of NSString.
#"Hello" <-- NSString object
"Hello" <-- Null-terminated char array (C-string)
You can even send messages to it:
[#"Hello" stringByAppendingString:#" World!"]
You will use NSString objects more often than C-strings.
If you want to convert a C-string to an NSString object (if you are using C libraries that return such strings for example), you could use this:
char *myCstring = "Hello, World!";
NSString *myString = [NSString stringWithUTF8String:myCstring];
About the two nibs: actually you don't need any nibs at all, but Apple likes to decrease performance by using a nib that only has one window. I don't know why they do it, but you can create a window in code with only one line, which compiles and runs much faster.
In your applicationDidFinishLaunching: method:
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = [[[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil] autorelease];
// now you can remove the MainWindow.xib nib.
Personally I prefer to use no nibs at all, but that's one's own choice.

Proper Memory Management for Objective-C Method

I'm programming an iPhone app and I had a question about memory management in one of my methods. I'm still a little new to managing memory manually, so I'm sorry if this question seems elementary.
Below is a method designed to allow a number pad to place buttons in a label based on their tag, this way I don't need to make a method for each button. The method works fine, I'm just wondering if I'm responsible for releasing any of the variables I make in the function.
The application crashes if I try to release any of the variables, so I'm a little confused about my responsibility regarding memory.
Here's the method:
FYI the variable firstValue is my label, it's the only variable not declared in the method.
-(IBAction)inputNumbersFromButtons:(id)sender {
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
NSString *placeHolderString = [[NSString alloc] init];
placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
NSString *addThisNumber = [[NSString alloc] init];
int i = placeHolderButton.tag;
addThisNumber = [NSString stringWithFormat:#"%i", i];
NSString *newLabelText = [[NSString alloc] init];
newLabelText = [placeHolderString stringByAppendingString:addThisNumber];
[firstValue setText:newLabelText];
//[placeHolderButton release];
//[placeHolderString release];
//[addThisNumber release];
//[newLabelText release];
}
The application works fine with those last four lines commented out, but it seems to me like I should be releasing these variables here. If I'm wrong about that I'd welcome a quick explanation about when it's necessary to release variables declared in functions and when it's not. Thanks.
Yes, you need to release them, but you need them just a little longer than beyond the end of your function.
The solution is called autorelease. Just replace release with autorelease and the objects stay around until the program gets back to the runloop.
When the program gets back there, everybody interested in one of the objects should have sent a retain message to it, so the object will not be deallocated when released by the NSAutoreleasePool.
edit actually, looking at your code, there's a lot more wrong with it. E.g. this:
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
doesn't make sense. First you allocate an object, then assign (a pointer to) it to variable placeHolderButton. That's fine.
Then you assign sender to that same variable. The reference to the object you just created is now lost.
Not sure if I get what you want, but this would be better:
-(IBAction)inputNumbersFromButtons:(id)sender {
UIButton *placeHolderButton = sender; // this is still a little useless, but ok
int i = placeHolderButton.tag;
NSString *addThisNumber = [NSString stringWithFormat:#"%i", i];
NSString *placeHolderString = firstValue.text;
NSString *newLabelText = [placeHolderString stringByAppendingString:addThisNumber];
[firstValue setText:newLabelText];
}
No allocs, so no releases necessary. The strings returned by those functions are already added to the autoreleasepool, so they will be deallocated automatically (if needed).
Well. Release them when you are done with them. The sooner the better. Some objects are tricky if you are new to memory management.
Release them in the dealloc method then.
The auto release pool can be handy, some people might disagree according to the performance issues.
you need to release anything containing the word new, alloc/init or copy.
also, you don't need to alloc/init this:
UIButton *placeHolderButton = [[UIButton alloc] init];
placeHolderButton = sender;
another way of doing this is:
UIButton *placeHolderButton = (UIButton *)sender;
in your version, it is allocating an instance with a retain count of +1, but you are immediately replacing the reference, so there is no way of releasing the memory later.
you are creating a lot of instances with alloc/init, and then replacing their references with autoreleased instances.
you could use
NSString *placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
instead of
NSString *placeHolderString = [[NSString alloc] init];
placeHolderString = [placeHolderString stringByAppendingString:firstValue.text];
which is again replacing a manually managed instance created on the first line, with an autoreleased instance on the second.
infact you could replace every alloc/init in this with the factory method and not have to deal with memory at all in it as they would be autoreleased instances.
-(IBAction)inputNumbersFromButtons:(id)sender {
//cast sender as a UIButton to suppress compiler warning, and allow us to reference it as placeholder button
UIButton *placeHolderButton = (UIButton *) sender;
int i = placeHolderButton.tag;
NSString *addThisNumber = [NSString stringWithFormat:#"%i", i];
[firstValue setText:[firstValue.text stringByAppendingString:addThisNumber]];
}
If you look at the class docs for NSString, any method with a + next to it(ie +stringWithString:(NSString *)string) is a class method, don't use these methods on a reference after you have called alloc/init on it.
I find it puzzling that you use alloc/init on a UIButton.
I always use the factory methods, e.g.
UIButton* aButton = [UIButton buttonWithType:UIButtonTypeCustom];
This returns an autoreleased button which I immediately add to its intended parent view.
Can't confirm it right now, but it looks as if the SDK caches UIButton instances and performs some optimizations behind the scenes. Every time I tried to retain a UIButton ivar, performance has degraded (especially when there is many sub views on screen)

ObjC: How bad is to directly assign to a property and the release it?

I'm wondering how bad is the following code for experienced objective-C programmers.
self.request = [[ASIHTTPRequest alloc] initWithURL:url];
[self.request release];
It is definitely less verbose this
ASIHTTPRequest *tmp = [[[ASIHTTPRequest alloc] initWithURL:url];
self.request = tmp;
[tmp release];
But I'm not sure if it is meaningful enough or doesn't lead to bugs.
What do you think?
UPDATE:
I don't want to use autorelase pools as my app is going to run on iphone where memory is limited.
UPDATE: I don't want to use autorelase pools as my app is going to run on iphone where memory is limited.
Do use the autorelease pools! Cocoa touch framework itself uses them; making one or two autorelease'ed objects yourself doesn't change the big picture.
It's true Apple warns you against excessive reliance on autorelease pools on iPhone, like putting hundreads of objects before the pool gets drained after the conclusion of the event dispatch, but excessive avoidance of autorelease pools is also counter-productive!
Nothing is black and white; nirvana is in the middle way.
Why not this?
self.request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
Or, if this is a class you wrote or have the source for, create a new class method (not instance) that does essentially the same thing (assuming NSURL * argument):
+ (ASIHTTPRequest *) requestWithURL:(NSURL *)url
{
return [[[self alloc] initWithURL:url] autorelease];
}
Definitely go with the latter, although choose a more descriptive name instead of tmp. You are responsible for releasing tmp, but you are not responsible for releasing self.request, at least not in the context given.
Alternatively, if you don't mind adding things to the autorelease pool, simply do:
self.request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
or
self.request = [ASIHTTPRequest requestWithURL:url];
What you missed is not the difference in verbosity but the memory management difference.
You often see code like this:
ASIHTTPRequest * requestTmp = [[[ASIHTTPRequest alloc] initWithURL:url];
self.request = requestTmp;
[requestTmp release];
You should consider what is happening if the property is retained and old one released in the setter method.
What this mean is that you create new request, refcount is 1.
self.request = request, now if setRequest looks like:
- (void)setRequest:(ASIHTTPRequest*)aReq
{
[aReq retain];
[request release];
request = aReq;
}
This means that the object retained the requestTmp you passed in and released the old one. Refcount of requestTmp is now 2.
After this call you can then release your original requestTmp that you created and you are safe because the object retained the requestTmp - refcount is still 1.
However if you do this:
self.request = [[ASIHTTPRequest alloc] initWithURL:url];
[self.request release];
you end up releasing the request that the object retained for its use. Note that you are release object's internal request where in the original case you released the tmp but the object keeps it's own retained reference.
So the result is different from the original code.

nesting "alloc" with a setter in Objective-C

first question here, this is regarding the iPhoneOS3 not MacOSX. I am fairly new to Objective-C and I've never developed in a environment without automatic garbage collection so I am a little confused by this. Here's some valid code assigning a view controller to an app delegate from an example off Apple.com:
MyViewController *aViewController = [[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
[self setMyViewController:aViewController];
[aViewController release];
So, from what I understand, I must release aViewController because it is first allocated (+1 = 1); then retained in the setter (+1 = 2); then released in the setter (-1 = 1); and then no longer needed so finally released again (-1 = 0) and the memory is freed. Wel could I not just skip assigning the temporary object aViewController and nest these functions like so:
[self setMyViewController:[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]]];
I was wondering if this would work correctly? I am a little worried since the setter requires a pointer-to-ViewController instead of just a copy of one. And since I am only passing a return value, is the pointer-to-ViewController in the setter going to point to data that may be erased or lost before it can assign it? I am sorry if this seems like a dumb question, but I am having a hard time finding an answer anywhere, and I am trying to establish good techniques for non-garbage collection environments. Thanks!
Don't think of memory management in terms of absolute retain counts. Think of it entirely in terms of ownership and encapsulation.
When you alloc an object, you have created an object that you own. When you set that object as a value on another object, that other object should retain the object to express ownership. If your code is no longer interested in the object, you should then release (or autorelease it if you want to return it to something else).
[self setMyViewController:[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]]];
To answer your specific question, the above line of code, by itself, will cause a memory leak assuming that -setMyViewController: is implemented correctly.
I've decided that this code works sufficiently and doesn't cause a memory leak:
MyViewController *aViewController = [[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]] autorelease];
[setMyViewController:aViewController];
Thanks for all the help guys!
[self setMyViewController:[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]]];
here you allocate, then it is retained, so straight away you have a retain count of 2. but it would get set correctly, as you still pass the setter a pointer to the view controller.
If the property MyViewController was of type assign (not retain), you would only have a retain count of 1.