PDA

View Full Version : Learning Mac programming with iPhone background




dantastic
May 13, 2011, 05:52 AM
Hi there,

A while back I started developing for the iPhone coming from a mostly Java background. That was fine, plenty of reading material that explained things and drilled in a few best practices along the way.

I found myself the other day needing a pretty basic app to help me draw out Bezier Curves and getting their coordinates. Not being able to find an app out there I figured it would be a handy learning exercise to write one myself.

I found first that cocoa was a bit different from cocoa touch so I picked up the most recommended book out there and figured - I'll just start from the beginning. So I'm about 150 pages in to - cocoa programming for mac osx.

I find because I probably learned things in the wrong order - every page I read the more confused I get!

I have a pretty good grasp of objective-c but the cocoa part is killing me. Do anyone know of any resources what would be better at explaining these things to someone already proficient in cocoa touch?



chown33
May 13, 2011, 01:29 PM
Describe what chapter you're on, and exactly what things are confusing.

The most common confusing things in Cocoa GUI development is probably first-responder and the whole "file's owner" relationship to a nib. MVC is in there, too. But those are essentially the same between Mac and iOS Cocoa, so I don't see the problem there.

Mac programs often have multiple windows, but other than document-based designs, that's just a top-level container for NSView objects: again, pretty much the same.

dantastic
May 13, 2011, 02:35 PM
I'm on chapter 8 at the moment - that's when I really hit the wall. I was pulled away on a job at the same time so I got most of the way through chapter 8 but I will have to start that chapter from scratch.

The first thing I'm not getting is the memory management. After having been on the iPhone for a while now I'm obviously pretty strict but in cocoa - does it just happen automatically?? I see alloc after alloc but no matching release. Then in some places he is setting up autorelease pools - do they cover objects I own as well?

Where I'm really stuck is in the Bindings - I don't understand what they are. I was blindly following along clicking things in the bindings inspector.

I understand the MVC design pattern, I understand the language. I think I will understand memory management pretty quickly too - the bindings I don't know what they are :)

chown33
May 13, 2011, 02:47 PM
The first thing I'm not getting is the memory management. After having been on the iPhone for a while now I'm obviously pretty strict but in cocoa - does it just happen automatically?? I see alloc after alloc but no matching release. Then in some places he is setting up autorelease pools - do they cover objects I own as well?

Memory management is the same on Mac as it is on iOS. At least if you're using retain/release. Retain/release is mandatory on iOS, but optional on Mac OS; the latter also offers garbage collection.

See the Memory Management Guides:
http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

If you look carefully you'll see the documentation is identical.


Post an example of the "alloc after alloc but no matching release". Are you sure the example isn't using garbage collection? Because that's exactly what I'd expect to see if GC is enabled.

Also post an example of "setting up autorelease pools". Because those would be unnecessary under GC.

dantastic
May 14, 2011, 03:26 AM
Ok, the application in chapter 3. it's small enough that I can post it in it's entirety here. This here is the example that got me confused about memory management.

#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; i++) {
NSNumber *number = [[NSNumber alloc] initWithInt:i * 3];
[array addObject:number];
}
for (int i = 0; i < 10; i++) {
NSLog(@"index: %i, number: %i", i, [[array objectAtIndex:i] intValue]);
}
[pool drain];
return 0;
}


In the above there's an autorelease pool created, will that also take care of my NSMutableArray array that I alloc and all the instances of NSNumber I alloc? From my understanding of using autorelease pools in cocoa touch they only release memory of autoreleased objects. ie:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *allocatatedString = [[NSString alloc] initWithString:@"Hello"];
NSString *autoreleasedString = [NSString stringWithFormat:@"World"];
[pool drain];
NSLog(@"%@ %@", allocatatedString, autoreleasedString);

(I haven't tested the above...) But in the above only hello should be printed. the autoreleasedString should be long gone but the contents of the allocatedString should remain untouched by the autorelease pool.

McGordon
May 14, 2011, 05:29 AM
The example is from Chapter 3, before Chapter 4 which is Memory Management.

I would say that example was leaking memory: the NSMutableArray and all the NSNumber objects. I think he's just ignoring the memory management at that point in the book to keep it simple and he does refer you forward to the next chapter in a couple of places, saying that autorelease pools will be discussed there.

jiminaus
May 14, 2011, 05:44 AM
In the above there's an autorelease pool created, will that also take care of my NSMutableArray array that I alloc and all the instances of NSNumber I alloc? From my understanding of using autorelease pools in cocoa touch they only release memory of autoreleased objects.

If this is not running in a GC environment, then indeed the NSArray object assigned to array and each of the NSObject objects assigned in turn to number will be leaked. As you know from Cocoa Touch (Cocoa is the same), the autorelease pool won't send release to these objects because they're not sent an autorelease message.

In a GC environment this code is fine. A drain message sent to an autorelease pool under GC is (virtually) a no-op. An autorelease message is a no-op (short-circuited by the runtime in objc_msgSend). Apple made efforts to allow autorelease pools and retain/release/autorelease to be efficiently used in a GC environment to allow libraries to be used in both GC and non-GC environments.

The example is from Chapter 3, before Chapter 4 which is Memory Management.

I would say that example was leaking memory: the NSMutableArray and all the NSNumber objects. I think he's just ignoring the memory management at that point in the book to keep it simple and he does refer you forward to the next chapter in a couple of places, saying that autorelease pools will be discussed there.

Yes I think you're right. The author's just trying to get you used to the syntax at this point. The only reference to destroying an object is on page 34.


What about destroying the object when you no longer need it? Chapter 4 talks about this (and all things NSAutoreleasePool-related).

dantastic
May 14, 2011, 08:26 AM
In a GC environment this code is fine. A drain message sent to an autorelease pool under GC is (virtually) a no-op. An autorelease message is a no-op (short-circuited by the runtime in objc_msgSend). Apple made efforts to allow autorelease pools and retain/release/autorelease to be efficiently used in a GC environment to allow libraries to be used in both GC and non-GC environments.


right, so in a GC environment the collector is taking care of all objects I explicitly own as well (though alloc for instance). But then effectively having a autorelease pool in the above snippet is essentially useless at the same time.

So for the code to be (more) correct I should either release all objects I own - like in a non garbage collected environment (cocoa touch). Or enable GC and remove the autorelease pool altogether.

In that case, in a GC environment is there any effective difference between

NSString *allocatatedString = [[NSString alloc] initWithString:@"Hello"];
NSString *autoreleasedString = [NSString stringWithFormat:@"World"];


I'll go through chapter 4 again and hopefully things will click. I'm quite open to the fact that I'm wrong here and I do appreciate the explanations given.

Sydde
May 14, 2011, 09:47 AM
right, so in a GC environment the collector is taking care of all objects I explicitly own as well (though alloc for instance). But then effectively having a autorelease pool in the above snippet is essentially useless at the same time.

So for the code to be (more) correct I should either release all objects I own - like in a non garbage collected environment (cocoa touch). Or enable GC and remove the autorelease pool altogether.

In that case, in a GC environment is there any effective difference between

NSString *allocatatedString = [[NSString alloc] initWithString:@"Hello"];
NSString *autoreleasedString = [NSString stringWithFormat:@"World"];


I'll go through chapter 4 again and hopefully things will click. I'm quite open to the fact that I'm wrong here and I do appreciate the explanations given.

In the first example, no autoreleased objects are created in the first place, so the pool does absolutely nothing, neither in a reference counted nor a GC environment.

Generally speaking (not always), in a reference counted environment, you would want to (auto-)release anything you add to an array if the array is the primary owner of the object (but you already knew that). In a GC environment, autoreleased objects are approximately equivalent to regularly allocated objects. They go away eventually if you do not have them in some object's set of properties (ivars).

Really, I think GC is not a good thing to teach off the bat. New programmers should learn memory management and use it as much as possible. GC is handy for Q&D applications, but when it comes to larger, more complex programs, I think your overall memory footprint will most likely go up somewhat with GC, since it only "gets around to" releasing garbage.

dantastic
May 14, 2011, 01:14 PM
In the first example, no autoreleased objects are created in the first place, so the pool does absolutely nothing, neither in a reference counted nor a GC environment.

That's right actually, in that example there are no autoreleased objects created - having that autorelease pool there to begin with is completely futile. I think I get the memory management now. I was just a bit confused by the code samples.

I'll carry on with the book and I'll try to figure out the bindings as well and what they are.

firewood
May 14, 2011, 06:27 PM
But then effectively having a autorelease pool in the above snippet is essentially useless ...

Only if you don't care about portability or reuse. I've been trying to write my Cocoa stuff so that I can reuse as much as possible of it on Cocoa Touch with minimal modification. And vice versa.

Reason: I've been porting an app from iPad to Mac OS X. Figured out a few improvements to some classes, and ported them back. Figure out some bug fixes and ported them forward. etc. I've been gradually reducing the differences to a few paradigm #ifdefs.

Also if you don't care about an optional bit of performance. Manual memory management usually requires less CPU cycles and dcache thrashing than GC. I'm old fashioned and hate to waste cycles on GC.

jiminaus
May 14, 2011, 06:37 PM
Draining an autorelease pool is not completely useless under GC.

From the Garbage Collection API chapter of the Garbage Collection Programming Guide:

NSAutoreleasePool

-(void)drain
Triggers garbage collection if memory allocated since last collection is greater than the current threshold. (This method ultimately calls objc_collect_if_needed().)



So the motivation for using autorelease pools above and beyond the one's provided by the normal run loop mechanism still applies equally to both GC and non-GC environments.