PDA

View Full Version : Just starting out at Objective-C, few noob questions




SanderDeclerck
Nov 9, 2010, 05:37 AM
For now, I only got one question, but i'm pretty sure I'll be having a few more in the next couple of days, and I don't want to open a new topic for each of my noob questions :-).

So, I just started programming in Objective-C (just bought the book "Learn Objective-C on the Mac"), but I do have some experience programming in windows (vb, c# and java). So my first question really comes from that background.

In c# and java, for instance, you can have a list of objects from a specific type (called generics):
C#:
List<Rectangle> rectangles = new List<Rectangle>();

Java:
ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>();

Is it correct to say that the NSMutableArray is the equivalent for the List in c# and the ArrayList in java, and is there a way to use generics (or any way to specify the object type for the elements in an array) in Objective-C?



Menge
Nov 9, 2010, 05:43 AM
There's no genetics or templates in Objective-C. The NSArray or NSMutableArray class holds any kind of Objective-C instances except that the Mutable variant is... Mutable.

whooleytoo
Nov 9, 2010, 06:50 AM
As said above, you can use NSArrays or NSDictionarys for collections of objects of varying classes. You can use "id" as the generic type.

If, for instance, you're iterating through an array of mixed objects and don't know what objects it contains, you can identify each one by using the className method; or you can use respondsToSelector: to verify if that object contains the required method before calling it.

MatthewF
Nov 9, 2010, 06:51 AM
And an example:
NSMutableArray* myArray = [NSMutableArray new]
//The object can be any Obj-C instance.
[myArray addObject: myObject];

gnasher729
Nov 9, 2010, 07:01 AM
There's no genetics or templates in Objective-C. The NSArray or NSMutableArray class holds any kind of Objective-C instances except that the Mutable variant is... Mutable.

You can of course use Objective-C++ (just use a file name that ends in .mm), so you have C++ with Objective-C extensions instead of C with Objective-C extensions. Whether that is a good idea is another matter. In general it is best to forget what C++ does and "go with the flow" of Objective-C: Use NSArray* and NSMutableArray* to hold arrays of objects, or NSDictionary* or NSSet*, whatever is better.


And an example:
NSMutableArray* myArray = [NSMutableArray new]
//The object can be any Obj-C instance.
[myArray addObject: myObject];

I'd suggest you use the alloc/init pattern instead:

NSMutableArray* myArray = [[NSMutableArray alloc] init];

because it is much more flexible and is generally what everybody uses. (Makes it possible to use initialisers other then plain init).

jared_kipe
Nov 9, 2010, 09:10 AM
Don't use NSObject's +new class method.

As gnasher has stated, Cocoa uses a two stage initialization with alloc/init, as well as designated initializers. This pattern is more robust and extensible.

The OTHER problem with +new is that it breaks Cocoa's own rules by returning a new object that is NOT autoreleased. Meaning that you own the object, and have to worry about releasing it when you are done.

Other Objective-C programmers will not like reading or debugging your code if you use +new for both of these reasons.


NSString *string = [NSString stringWithFormat: @"..."]; // autoreleased
NSNumber *num = [NSNumber numberWithDouble: 2.0]; // autoreleased
NSMutableArray *array1 = [NSMutableArray array]; // autoreleased
NSMutableArray *array2 = [NSMutableArray new]; // NOT autoreleased
[array1 addObject: string];
[array1 addObject: num];
[array2 addObject: string];
[array2 addObject: num];
//.....
return; // leaks an NSMutableArray, a NSString, a NSNumber

SanderDeclerck
Nov 9, 2010, 09:25 AM
Something else I'd like to know is the following:

I'm still a student, in school we're seeing java and c#, not objective-c. So, if I study Objective-C on my own, I cant prove I can program in it. So, my question is: does Apple have some form of certification for developers?

lee1210
Nov 9, 2010, 09:29 AM
Something else I'd like to know is the following:

I'm still a student, in school we're seeing java and c#, not objective-c. So, if I study Objective-C on my own, I cant prove I can program in it. So, my question is: does Apple have some form of certification for developers?

No, they don't. Even if they did, certs prove nothing. Write some things in Objective-C. Have it available to an interviewer on a USB stick.

-Lee

SanderDeclerck
Nov 9, 2010, 09:36 AM
No, they don't. Even if they did, certs prove nothing. Write some things in Objective-C. Have it available to an interviewer on a USB stick.

-Lee

That's a pity. I mean, you're completely right when saying they don't prove anything, but it can be the ticket to get the interview.

chown33
Nov 9, 2010, 11:36 AM
The OTHER problem with +new is that it breaks Cocoa's own rules by returning a new object that is NOT autoreleased.

This is incorrect because the rule is:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. ((Bold added for emphasis.))

http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH

Littleodie914
Nov 9, 2010, 12:17 PM
Don't use NSObject's +new class method.

As gnasher has stated, Cocoa uses a two stage initialization with alloc/init, as well as designated initializers. This pattern is more robust and extensible.

The OTHER problem with +new is that it breaks Cocoa's own rules by returning a new object that is NOT autoreleased. Meaning that you own the object, and have to worry about releasing it when you are done.

Other Objective-C programmers will not like reading or debugging your code if you use +new for both of these reasons.


NSString *string = [NSString stringWithFormat: @"..."]; // autoreleased
NSNumber *num = [NSNumber numberWithDouble: 2.0]; // autoreleased
NSMutableArray *array1 = [NSMutableArray array]; // autoreleased
NSMutableArray *array2 = [NSMutableArray new]; // NOT autoreleased
[array1 addObject: string];
[array1 addObject: num];
[array2 addObject: string];
[array2 addObject: num];
//.....
return; // leaks an NSMutableArray, a NSString, a NSNumber
I'm afraid that the leaks in your example would be blamed on programmer error. The [... new] method is analogous to [[... alloc] init], and when you instantiate an object using [... new], you're responsible for releasing it:


SomeClass *instance = [[SomeClass alloc] init];
[instance methodCall];
[instance release]; // Correct, no leak.

instance = [SomeClass new];
[instance methodCall];
[instance release]; // Also correct, no leak.


If you were planning on using [[... alloc] init], you can use [... new], though it is "going out of style."

SanderDeclerck
Nov 9, 2010, 01:32 PM
Ok, I just read the chapter on memory management, 1 thing isn't quite clear: when do we use garbage collection, and when not? I mean when we're programming for mac os x 10.5 and later, do we just always use garbage collection, or are there cases we're just using the "retain-release"-method?

lee1210
Nov 9, 2010, 01:39 PM
Ok, I just read the chapter on memory management, 1 thing isn't quite clear: when do we use garbage collection, and when not? I mean when we're programming for mac os x 10.5 and later, do we just always use garbage collection, or are there cases we're just using the "retain-release"-method?

Will you ever target at or below 10.4? Will you ever want to re-use this code on iOS? Do you have strict memory needs that are important for you to handle yourself to avoid huge bloat/swapping/etc.? The answers to these will determine what the "right thing" to do is.

10.4 and below can't use GC, and iOS doesn't support GC. With GC on you're leaving it to a magical entity outside of your control to free memory. Maybe it will never free it. Who knows?

Also, with GC in any language it's possible for you to "leak" references to an Object. It's not a true leak, because if it's outside of the object graph it will get GC'd, but you could have a reference that you forget about that results in an Object never getting GC'd. It's just something to look out for, and I mention it because i feel like when you read about GC it seems magic and "for free", when it really isn't.

-Lee

SanderDeclerck
Nov 9, 2010, 02:18 PM
Thanks for all those responses, i really appreciate it.

Another question (i'm really sorry, but i'll keep asking questions):
When you start typing "if" in Xcode, it adds code completions as follows:
if (condition) {
statements
}

However, I like my "{" at the beginning of the next line, like this:
if (condition)
{
statements
}

Is there a way to change that?

jared_kipe
Nov 9, 2010, 07:29 PM
I'm afraid that the leaks in your example would be blamed on programmer error. The [... new] method is analogous to [[... alloc] init], and when you instantiate an object using [... new], you're responsible for releasing it:


SomeClass *instance = [[SomeClass alloc] init];
[instance methodCall];
[instance release]; // Correct, no leak.

instance = [SomeClass new];
[instance methodCall];
[instance release]; // Also correct, no leak.


If you were planning on using [[... alloc] init], you can use [... new], though it is "going out of style."

Lets back up a bit. I'm not saying that it literally leaks, or literally breaks Cocoa's rules for returned objects. I'm saying from an end user's (programmers) standpoint it does.

It makes it harder spot mistakes and leaks (isn't every leak a mistake??). It prevents you from using a designated initializer other than init, it prevents you from calling +allocWithZone: (which alloc calls on its own).

jared_kipe
Nov 9, 2010, 07:31 PM
Ok, I just read the chapter on memory management, 1 thing isn't quite clear: when do we use garbage collection, and when not? I mean when we're programming for mac os x 10.5 and later, do we just always use garbage collection, or are there cases we're just using the "retain-release"-method?

I never use garbage collection. Honestly, retain-release is very easy to use properly.

Bernard SG
Nov 9, 2010, 07:57 PM
Thanks for all those responses, i really appreciate it.

Another question (i'm really sorry, but i'll keep asking questions):
When you start typing "if" in Xcode, it adds code completions as follows:
if (condition) {
statements
}

However, I like my "{" at the beginning of the next line, like this:
if (condition)
{
statements
}

Is there a way to change that?

Doesn't matter where you put the "{".

gnasher729
Nov 10, 2010, 04:31 AM
Lets back up a bit. I'm not saying that it literally leaks, or literally breaks Cocoa's rules for returned objects. I'm saying from an end user's (programmers) standpoint it does.

It makes it harder spot mistakes and leaks (isn't every leak a mistake??). It prevents you from using a designated initializer other than init, it prevents you from calling +allocWithZone: (which alloc calls on its own).

I think "new" was a misguided attempt to make C++ programmers more at home. Misguided because alloc + init is something very different from C++ new, once you get a bit deeper into things.

whooleytoo
Nov 10, 2010, 05:49 AM
Lets back up a bit. I'm not saying that it literally leaks, or literally breaks Cocoa's rules for returned objects. I'm saying from an end user's (programmers) standpoint it does.

It makes it harder spot mistakes and leaks (isn't every leak a mistake??). It prevents you from using a designated initializer other than init, it prevents you from calling +allocWithZone: (which alloc calls on its own).

It doesn't really make it much harder to spot mistakes. It's pretty easy, if you use the rough rule of thumb:

For every:
- new
- alloc
- copy
- retain

You need a:
- release
or
- autorelease

(and keep an eye on properties, which may have an implicit retain and release. One could argue - properties make it harder to spot leaks, more so than new!)

SanderDeclerck
Nov 11, 2010, 04:46 AM
In java, when you make a setter, it's no problem to give the parameter the same name as the instance variable, because you can use this.variableName to set the instance variable, like this:

public void setName(String name)
{
this.name = name;
}


What would be the equivalent of this in ObjectiveC?

Littleodie914
Nov 11, 2010, 07:01 AM
In java, when you make a setter, it's no problem to give the parameter the same name as the instance variable, because you can use this.variableName to set the instance variable, like this:

public void setName(String name)
{
this.name = name;
}


What would be the equivalent of this in ObjectiveC?There are a few different conventions. Since the name of the property you're setting is already in the method signature, for smaller methods like setters you can just use the first letter of the parameter:


- (void)setName:(NSString *)n {
if (name != n) {
if (name) {
[name release];
}
name = [n copy];
}
}


Alternatively, for larger methods (where it would be easy to lose a single-letter variable), you'll occasionally see the prefix 'a' in front of the variable names:


- (void)showEditWindow:(NSWindow *)aWindow withTitle:(NSString *)aTitle {
... // Code
}


Edit: Also, I'm surprised no one has mentioned CocoaDevCentral yet. One of the best sites out there for beginning and advanced Objective-C/Cocoa tutorials. Link (http://cocoadevcentral.com/)

whooleytoo
Nov 11, 2010, 09:38 AM
In java, when you make a setter, it's no problem to give the parameter the same name as the instance variable, because you can use this.variableName to set the instance variable, like this:

public void setName(String name)
{
this.name = name;
}


What would be the equivalent of this in ObjectiveC?

Typically you'd use the following convention:

In your .h file:
NSString* employeeName;

In your .m file:
[self setEmployeeName: @"John Smith"];
NSString* theName = [self employeeName];

However, for getter/setter methods, you should look at properties. They might confuse you a little at first, but they are very useful.

In your .h file:
NSString* employeeName;
..
@property (nonatomic, retain) NSString* employeeName;

In your .m file:
@synthesize employeeName;
..
self.employeeName = @"John Smith";
NSString* theName = self.employeeName;
self.employeeName = nil;

Why use properties?
- You don't have to write lots of get & set accessors. The synthesize directive tells the compiler to generate the getter and setter methods. Even though you haven't written them in this sample, they are there. With the first (non property example) you'd have to write the setEmployeeName: and employeeName methods.

- If in C you write employee1.salary, that's reading the salary directly from an instance variable. Now, let's say the system becomes more comples, and you now need to call a method to calculate the salary. You have to rewrite every reference to "salary" to call that new method instead.

In Obj-C, you can simply slot in a new "getter" method, which does the calculations. And you don't have to change the calling code! employee1.salary will first call the getter method. So it works regardless of whether salary is a fixed number that you store or a more dynamic number that you need to calculate in a method.

I hope that helped rather than confused! ;)

SanderDeclerck
Nov 11, 2010, 10:22 AM
Again, thanks for the very helpful answers I've been getting in this topic!

@whooleytoo: apparently the next chapter I had to read in the book I bought ("Learn Objective-C on the Mac"), was titled: "Properties" :-).