Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Ja Di ksw

macrumors 65816
Original poster
Apr 9, 2003
1,313
8
Hi everyone, noobie type question here, I could even just use a link that says "read this for that topic" if it's long to explain.

I want to have a 2D simulation, with units moving around the screen. Each unit has the same variables as the other units, yet it will have its own values for the variables that can change over time and are unit specific (i.e., a unit runs into "energy" and the energy variable increases in value for that unit, but no other). From what I've read in "Programming in Objective-C, 2nd edition" I thought it would be ideal to have an object class for these units, and have each unit be an instance of that class. And for units that are defined from the start, it's looking good (nowhere near done programming yet).

However, I wanted the units to be able to "reproduce" (i.e., if the energy variable's value goes above 50, a new unit/object instance is created). Is this possible with each unit being an instance object? I'm asking because when I make a method that returns an object instance (new unit), it looks like I have to define the new instance ahead of time:

This works:
Code:
UnitsClass *newObject = [[UnitsClass alloc] init];
newObject = [oldObject reproduce];

This obviously doesn't:
Code:
newObject = [oldObject reproduce];
(error: You are too old to start learning programming and probably drunk)


But I can't have an alloc init for each new unit/instance that may or may not appear, because depending on how long the program runs it could have 5 new units or 50,000 new units.

Thanks in advance for any help :)
 
Last edited by a moderator:
The alloc/init pair creates space for a new instance and init initialises it. You should only call this when you want a new/blank instance. In your example your reproduce method would create a new instance and populate it with the correct values. In this case you would not call alloc/init (the reproduce method would). You don't need alloc/init for each variable declaration: they are 100% not linked together.

As you are going to have lots of instances I would suggest using a NSMutableArray or similar to hold them rather than loads of variables.
 
The alloc/init pair creates space for a new instance and init initialises it. You should only call this when you want a new/blank instance. In your example your reproduce method would create a new instance and populate it with the correct values. In this case you would not call alloc/init (the reproduce method would). You don't need alloc/init for each variable declaration: they are 100% not linked together.

As you are going to have lots of instances I would suggest using a NSMutableArray or similar to hold them rather than loads of variables.

Thank you for the help, I'll read up on NSMutableArrays, I'm not quite sure I understand what you mean, though.

If I use "newObject = [oldObject reproduce];" without first saying that there is a "newObject" is gives the error "Use of undeclared identifier 'newObject'

FWIW, the reproduce method contains "UnitsClass *newObject = [[UnitsClass alloc] init];" and gives it some values, but that has to be returned to something. I can't just say '[oldObject reproduce]' without setting it to equal another instance, and so don't I have to define that instance first?
 
Thank you for the help, I'll read up on NSMutableArrays, I'm not quite sure I understand what you mean, though.

If I use "newObject = [oldObject reproduce];" without first saying that there is a "newObject" is gives the error "Use of undeclared identifier 'newObject'

FWIW, the reproduce method contains "UnitsClass *newObject = [[UnitsClass alloc] init];" and gives it some values, but that has to be returned to something. I can't just say '[oldObject reproduce]' without setting it to equal another instance, and so don't I have to define that instance first?

I did not say not to declare the variable. I said not to create a new instance and assign it to the variable. I think you need to step back and understand some fundamentals.

What does = mean? How does

Code:
UnitsClass *newObject;

differ from

Code:
UnitsClass *newObject = [[UnitsClass alloc] init];
?
 
Thank you for the help, I'll read up on NSMutableArrays, I'm not quite sure I understand what you mean, though.

If I use "newObject = [oldObject reproduce];" without first saying that there is a "newObject" is gives the error "Use of undeclared identifier 'newObject'

FWIW, the reproduce method contains "UnitsClass *newObject = [[UnitsClass alloc] init];" and gives it some values, but that has to be returned to something. I can't just say '[oldObject reproduce]' without setting it to equal another instance, and so don't I have to define that instance first?

what you are asking to do can't really be done in objective-c, at least not the way you are wanting to go about doing it. you can't dynamically create variables and then allocate them. you would need to "pre configure" in your code variable names that can be accessed. so for instance you can't say "newObject1 = blah blah", and then magically create a newObject2, newObject3, newObject4, etc without statically specifying those names. you can how ever use arrays like the one poster mentioned. an array is a "container" of objects. a "mutable" array is a dynamic container of objects that automatically grows and shirks depending on how many objects are contained within. the objects are accessed by an "index" number handled by the array. so you could do something like

Code:
NSString *string1 = @"Monday";
NSString *string2 = @"Tuesday";
NSString *string3 = @"Wednesday";
NSString *string4 = @"Thursday";
NSString *string5 = @"Friday";

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

[myStringsArray addObject:string1];
[myStringsArray addObject:string2];
[myStringsArray addObject:string3];
[myStringsArray addObject:string4];
[myStringsArray addObject:string5];

you would then end up with a container of all those strings each accessible by an index number starting at 0. so if i wanted say "string3" i could do something like this

Code:
 NSLog(@"%@ is Hump Day", [myStringsArray objectAtIndex:2]);

the resulting output would be
Code:
 Wednesday is Hump Day

the power of arrays (and dictionaries) are there ability to store vast numbers of objects and to be able to do so dynamically. you can use them in for loops and add a dynamic amount of objects or even methods. so for instance you could do this

Code:
 [myStringsArray addObject:[oldObject reproduce]];


you could then use that later on and do something like

Code:
 SomeClass *myNewThing = [myStringsArray objectAtIndex:5];

the outcome would be your "myNewThing" would be the result of "[oldObject reproduce]".


you can even store arrays & dictionaries in other arrays or dictionaries. this concept is referred to as "nested arrays" or "nested dictionaries".
 
Last edited:
Cocoa Core Competencies: Collection:
https://developer.apple.com/library...conceptual/devpedia-cocoacore/Collection.html

Collections Programming Topics:
https://developer.apple.com/library/Mac/DOCUMENTATION/Cocoa/Conceptual/Collections/Collections.html

These reference docs are already written, have been read by thousands of people, and are kept updated by Apple.


If you didn't know about NSArray, or any other collection class, then you should probably read a more structured tutorial or book that covers these fundamental classes.
 
I prefer:

Code:
UnitsClass *newObject = nil;
newObject = [oldObject reproduce];

so that newObject isn't junk, even if I forget or mistype the following assignment.
 
I prefer:

Code:
UnitsClass *newObject = nil;
newObject = [oldObject reproduce];

so that newObject isn't junk, even if I forget or mistype the following assignment.

Just saying: You should turn all reasonable warnings in Xcode, set "warnings = errors", and turn on the static analyzer.

If you forget or mistype the following assignment, you get a warning that newObject isn't initialised, which is turned into an error, and your program will not build. By initialising newObject to nil, you prevent the compiler from checking.
 
I have yet to see evidence that this pedantic style of coding increases productivity for the most interesting software solutions.

It surely finds errors.

It finds the mistakes that anybody makes while developing and fixes them quicker.

It reduces the number of crashes when your code is in the hand of the customer.

It improves what kind of code you write in the long term.
 
It surely finds errors.

It finds the mistakes that anybody makes while developing and fixes them quicker.

It reduces the number of crashes when your code is in the hand of the customer.

It improves what kind of code you write in the long term.

It also throws up all sorts of warnings because I'm trying to code in a way that will work for both OS X 10.5.0 (over 6 years old) and beyond OS X 10.9.0 (not yet released.) Supporting Leopard is trivial so I don't see a reason not to... it's supporting both Snow Leopard and Lion that makes me have to do things weird... plus supporting Core Solo...

With new projects I'm going to be ditching Core Solo and Snow Leopard, but in the meantime since the code was written two years ago to support those platforms I'll just keep supporting them with this project... even though it means a long list of warnings.
 
It surely finds errors.

It finds the mistakes that anybody makes while developing and fixes them quicker.

It reduces the number of crashes when your code is in the hand of the customer.

Thus making errors, mistakes and bugs more important, and take up a greater percentage of limited brain cycles and neurons, than good creative solutions.
 
I prefer:

Code:
UnitsClass *newObject = nil;
newObject = [oldObject reproduce];

so that newObject isn't junk, even if I forget or mistype the following assignment.

"newObject" well never be junk. objective-c always initializes new objects to nil. that first line of code is just redundant.
 
"newObject" well never be junk. objective-c always initializes new objects to nil. that first line of code is just redundant.

Sorry, that's only true for static storage and for instance vars. An 'auto' variable (i.e. defined within a function or method body, and not declared static) has an undefined value until it's been initialized or assigned a value. The C-recognized keyword for local variables is 'auto', as distinct from C's other storage-class keywords: static and register.

Since the example is clearly executable code, it can only reside within a function or method body, and the implicit storage class of newObject will be auto.

This behavior (or misbehavior) is inherited from C, whose standard defines no specific value for uninitialized auto variables.

http://en.wikipedia.org/wiki/Automatic_variable
 
Sorry, that's only true for static storage and for instance vars. An 'auto' variable (i.e. defined within a function or method body, and not declared static) has an undefined value until it's been initialized or assigned a value. The C-recognized keyword for local variables is 'auto', as distinct from C's other storage-class keywords: static and register.

Since the example is clearly executable code, it can only reside within a function or method body, and the implicit storage class of newObject will be auto.

This behavior (or misbehavior) is inherited from C, whose standard defines no specific value for uninitialized auto variables.

http://en.wikipedia.org/wiki/Automatic_variable

Apple disagree

This isn’t necessary for object pointers, because the compiler will automatically set the variable to nil if you don’t specify any other initial value:
Code:
    XYZPerson *somePerson;

    // somePerson is automatically set to nil
 

When ARC is turned on.

With ARC, when you set a strong object pointer to any value, the object pointed to before must be released, unless it was nil. If the pointer was uninitialised (filled with rubbish data), that would be impossible to do right, so object pointers can never be allowed to be uninitialised. Even

Code:
NSObject* myObject;
myObject = nil;
couldn't work if the compiler didn't initialise myObject to nil.
 
When ARC is turned on.

With ARC, when you set a strong object pointer to any value, the object pointed to before must be released, unless it was nil. If the pointer was uninitialised (filled with rubbish data), that would be impossible to do right, so object pointers can never be allowed to be uninitialised. Even

Code:
NSObject* myObject;
myObject = nil;
couldn't work if the compiler didn't initialise myObject to nil.

Sorry, the link I posted doesn't go directly to the correct section. I think this one does. It says nothing about ARC. It simply says the compiler will automatically set the variable to nil for you.
 
Sorry, the link I posted doesn't go directly to the correct section. I think this one does. It says nothing about ARC. It simply says the compiler will automatically set the variable to nil for you.

It's in the iOS documentation, and I think they make a strong assumption nowadays that everyone uses ARC on iOS.
 
Sorry, that's only true for static storage and for instance vars. An 'auto' variable (i.e. defined within a function or method body, and not declared static) has an undefined value until it's been initialized or assigned a value. The C-recognized keyword for local variables is 'auto', as distinct from C's other storage-class keywords: static and register.

Since the example is clearly executable code, it can only reside within a function or method body, and the implicit storage class of newObject will be auto.

This behavior (or misbehavior) is inherited from C, whose standard defines no specific value for uninitialized auto variables.

http://en.wikipedia.org/wiki/Automatic_variable

you're confusing objects with primitives. as i said, objects will always be set to nil as apple and other posters have said as well.
 
you're confusing objects with primitives. as i said, objects will always be set to nil as apple and other posters have said as well.

Only when ARC is enabled. Without ARC:

Code:
int main(int argc, const char * argv[])
{

	@autoreleasepool {
		NSString* tmp;
	    
	    // insert code here...
	    NSLog(@"tmp = %@", tmp);
	    
	}
    return 0;
}

Compiler says:
/Users/.../main.m:18:25: warning: variable 'tmp' is uninitialized when used here /Users/.../main.m:15:16: note: initialize the variable 'tmp' to silence this warning

Analyser says:
/Users/../main.m:18:6: Function call argument is an uninitialized value
 
Only when ARC is enabled. Without ARC:

Code:
int main(int argc, const char * argv[])
{

	@autoreleasepool {
		NSString* tmp;
	    
	    // insert code here...
	    NSLog(@"tmp = %@", tmp);
	    
	}
    return 0;
}

Compiler says:
/Users/.../main.m:18:25: warning: variable 'tmp' is uninitialized when used here /Users/.../main.m:15:16: note: initialize the variable 'tmp' to silence this warning

Analyser says:
/Users/../main.m:18:6: Function call argument is an uninitialized value

who doesn't use ARC these days? there isn't any rock solid reasons not to be using it at this point.
 

It doesn't mention ARC on that page, but the document as a whole definitely strikes me as being written with the assumption that ARC is enabled. AFAICT, they don't actually say this explicitly anywhere, but it becomes apparent in several places if one is already familiar with non-ARC conventions.

There is a mention of ARC in the Introduction section:
https://developer.apple.com/library...n.html#//apple_ref/doc/uid/TP40011210-CH1-SW1
...
Objective-C apps use reference counting to determine the lifetime of objects. For the most part, the Automatic Reference Counting (ARC) feature of the compiler takes care of this for you. If you are unable to take advantage of ARC, or need to convert or maintain legacy code that manages an object’s memory manually, you should read Advanced Memory Management Programming Guide.
Since they don't tell you the Advanced Memory Management Guide is required reading, it strongly suggests to me it that ARC will be used. If ARC weren't being used, or the document covered both memory management models equally, then a very different document would almost certainly result, because retain/release is a fundamental aspect, not a "See Also" one.

Again, under "Encapsulating Data : Manage the Object Graph through Ownership and Responsibility" the concept of ownership and strong references is presented entirely as ARC rules, not retain/release.
https://developer.apple.com/library...a.html#//apple_ref/doc/uid/TP40011210-CH5-SW3
... In Objective-C, an object is kept alive as long as it has at least one strong reference to it from another object. ...​
This is clearly an ARC rule, not a retain/release one.

There are other places throughout the document that the presumption of ARC is evident. The last one I found was in the Revision History:
https://developer.apple.com/library....html#//apple_ref/doc/uid/TP40011210-CH99-SW1
2012-07-20 New document that describes elements of best practice when writing code with Objective-C using ARC.
The way I read that, they wrote a new document that tells how to write Objective-C using ARC.
 
who doesn't use ARC these days? there isn't any rock solid reasons not to be using it at this point.

Were we discussing that? No, we were discussing the fact that according to Apple's documentation the Objective-C compiler behaves in a way that is totally different from the behaviour of any C compiler in existence. And the fact that Apple's documentation doesn't mention the tiny little detail that it applies only to ARC.

And there are some pretty good reasons for some people to not use ARC. For example, using non-ARC source code from third parties with a license that makes it very hard legally to make any changes to the source code. Or having an old code base that relies heavily on Core Foundation.

So it's pretty important for many people that this applies only to ARC. And it is essential for everyone to know that htis applies only to Objective-C pointers, and not to any other pointers.
 
who doesn't use ARC these days? there isn't any rock solid reasons not to be using it at this point.

It doesn't compile for some targets. I forget which, but I tried using ARC in Battery Status and then discovered that roughly 30% of my users couldn't use the app anymore, so I shelved ARC.

Same goes for array and dictionary literal notation.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.