NSArray getter method not returning right value - objective-c

I'm making a program where one Class (classA) generates a random number and adds it to a mutable array. A view controller (viewControllerA) calls a method from classA and receives the array of random numbers and stores it in its own array.
I have another class (classB) that needs the same array. After viewcontrollerA is finished doing what it needs to do with the array, it calls the setter method for an array in classB. I call NSLog in the setter and getter methods for the array in classB to check to see if it loads.
-(void)setRandomNumberArray:(NSArray *)randomNumberArray{
_randomNumberArray = randomNumberArray;
NSLog(#"%# setter", _randomNumberArray);
}
-
-(NSArray *)randomNumberArray{
if (!_randomNumberArray) {
_randomNumberArray = [[NSArray alloc] init];
}
NSLog(#"%# getter", _randomNumberArray);
return _randomNumberArray;
}
When I call the setter method in viewControlerA, NSLog returns the value of the array.
When I call the getter method in viewControllerB, NSLog prints nothing from the getter method.
2012-05-29 23:57:43.589 SwipeGame[8603:f803] (
) getter
It's obviously setting the array but not retaining it for when i want to get it. What is going on? I've tried multiple other techniques and it always sets the array but doesn't retain it for when i want to "get" the array.
the property for my array is set to retain btw..
UPDATE:
Yes I am using ARC. my property declaration is:
#property (nonatomic, strong) NSArray *randomNumberArray
SOLVED:
Thanks for all your help! It was a problem with instances.

Your setter method does not mention viewControllerB. You are just setting an internal variable. How is viewControllerB going to know about the array having been set?
The easiest way is to just use #properties and #synthesize:
// in A
viewControllerB.array = _array;
As for the retain question: if you use ARC you should not worry about it.

Do you use ARC?
ARC version bellow:
#interface Foo : NSObject {
NSMutableArray *_randomNumberArray;
}
#property (nonatomic, strong) NSMutableArray *randomNumberArray;
#end
#implementation Foo
#synthesize randomNumberArray = _randomNumberArray;
- (void)setRandomNumberArray:(NSMutableArray *)randomNumberArray {
_randomNumberArray = randomNumberArray;
NSLog(#"%# setter", _randomNumberArray);
}
- (NSMutableArray *) randomNumberArray {
if ( _randomNumberArray == nil )
_randomNumberArray = [[NSMutableArray alloc] init];
NSLog(#"%# getter", _randomNumberArray);
return _randomNumberArray;
}
#end
Not ARC version bellow:
#interface Foo : NSObject {
NSMutableArray *_randomNumberArray;
}
#property (nonatomic, strong) NSMutableArray *randomNumberArray;
#end
#implementation Foo
#synthesize randomNumberArray = _randomNumberArray;
- (void)setRandomNumberArray:(NSMutableArray *)randomNumberArray {
[_randomNumber release];
_randomNumberArray = randomNumberArray;
[_randomNumberArray retain];
NSLog(#"%# setter", _randomNumberArray);
}
- (NSMutableArray *) randomNumberArray {
if ( _randomNumberArray == nil )
_randomNumberArray = [[NSMutableArray alloc] init];
NSLog(#"%# getter", _randomNumberArray);
return _randomNumberArray;
}
- (void)dealloc {
[_randomNumberArray release];
}
#end

If you are creating this random number array using an NSMutableArray, and passing that to the setter, the array could be mutated later by the caller (e.g. all items removed) and the array can change from under your feet.
For types like NSArray and NSString which have mutable subtypes, you should declare your property as copy instead of strong. This will ensure the array passed to you cannot be mutated at a later date by somebody else. Copy performance is not a problem because the regular immutable types handle copies very efficiently.

Related

In objective C lazy instantiation, why don't we touch the setter?

In objective C, its common practice to instantiate internal class arrays (and the like) in a lazy manner.
So if you call on the getter, it first checks if the array isn't nil, and allocates memory for it if needed.
But what about the setter?
If you are trying to insert some value into one of the array cells, since we did not allocate memory for it yet - where does it go?
I'm missing something here, clearly. Would be happy for a clarification.
I'm not sure I understand your question, but if you do this:
#property (nonatomic, strong) NSMutableArray* myArray;
...
- (NSMutableArray *) myArray {
if(!_myArray) {
NSLog(#"created");
_myArray = [[NSMutableArray alloc] init];
}
return _myArray;
}
...
[self.myArray addObject:#"test"];
The getter is actually getting called when you call addObject:, so you'll see "created" being logged.
So #property declarations are syntactic sugar for declaring, in the case of objects, pointers to instance variables. The "nonatomic" refers to the type of getter and setter automatically created (in this case "non thread safe.") And the "strong" is an indicator to ARC to increase the retain count of the variable.
So when you declare:
#property (nonatomic, strong) NSMutableArray* myArray;
This is what really gets created in your class - just a pointer to your hidden instance variable.
#implementation MyClass {
NSMutableArray *_myArray;
}
As you can see in the getter, you are initializing the _myArray pointer to point to a new NSMutableArray:
- (NSMutableArray *) myArray {
if(!_myArray) {
NSLog(#"created");
_myArray = [[NSMutableArray alloc] init];
}
return _myArray;
}
However in the setter, you are just updating the pointer to a variable you have already created.
self.myArray = [[NSMutableArray alloc] init];
This sends your class the following message:
- (void) myArray: (NSMutableArray *) myArray {
_myArray = myArray;
}
As you can, see the setter doesn't need any special initialization most of the time. The only time you want to create a custom setter is when you want to validate the incoming object has special properties. A contrived example is checking that the NSMutableArray is no larger than 10 objects:
- (void) myArray: (NSMutableArray *) myArray {
if (myArray.count < 10) {
_myArray = myArray;
}
}
Finally, I would like to point out that you can actually lazy instantiate objects using the short ternary operator and parenthetical return values. For example, the following statement:
- (NSMutableArray *) myArray {
return (_myArray = _myArray ?: #{}.mutableCopy);
}
Is equal to:
- (NSMutableArray *) myArray {
if(!_myArray) {
_myArray = [[NSMutableArray alloc] init];
}
return _myArray;
}
You can even macro this pattern into (WSM is my class prefix):
#define WSM_LAZY(object, assignment) (object = object ?: assignment)
So you can write statements like this:
- (NSMutableArray *) myArray {
return WSM_LAZY(_myArray, #{}.mutableCopy);
}
Or even use compound statement syntax to rewrite the original setter you presented as an example:
- (NSMutableArray *) myArray {
return WSM_LAZY(_myArray, ({
NSLog(#"created");
#{}.mutableCopy;
}));
}

iOS - NSMutableArray shows objects out of bounds on setting property

I have implemented the following code to assign NSMutableArray to a property -
NSMutableArray * anArray = [responseDictionary valueForKeyPath:#"tags"];
NSLog(#"The array length is=%d",[anArray count]);
for (NSString *s in anArray) {
NSLog(#"you are %#", s);
}
[self setActiveTagArray:anArray];
It prints out the string values fine. But in the setter function, if I place a breakpoint I see that it shows there are two objects but they are "Out of Scope". What does this mean? What am I doing wrong? My getter also does not fetch any values. The property functions -
-(void)setActiveTagArray:(NSMutableArray *)tags
{
activeTagArray = [[NSMutableArray alloc] init];
activeTagArray = tags;
//NSLog(#"%#",[activeTagArray count]);
}
-(NSMutableArray *)getActiveTagArray
{
return activeTagArray;
}
Is activeTagArray a class variable as well as a property. Consider using _activeTagArray as the class variable name. And then in the .m file just use #synthesize activeTagArray = _activeTagArray;, and for get the second two methods completely.
Response to comment:
You said "I have implemented the following code to assign NSMutableArray to a property". I took this to mean you have "#property (nonatomic, retain) NSMutableArray *activeTagArray;" in your .h file. If this is the case then you would access it thru otherObject'sNameForYourClassHere.activeTagArray.
#synthesize create accessors & mutators for you.

Properties and accessors in Objective-C

Does the following code call an accessor "set" function or does it modify the pointer myMember directly?
aClass.h
#interface MyClass : NSObject {
NSArray *myMember;
}
#property (nonatomic, retain) NSArray *myMember;
aClass.c
#implementation GameplayScene
#synthesize myMember;
- (id) init {
if ( (self = [super init]) )
{
myMember = [NSArray array];
}
}
In other words, I would like to know if the method setMyMember is being called, or if the pointer of myMember is being modified directly.
Likewise, is myMember = [NSArray array] identical to self.myMember = [NSArray array]?
Without the self. notation, the instance variable is modified directly. With it, the property setter is called (and since you made it a retain property, the new pointer that it's being set to will be sent a retain message).
See Apple's documentation on declaring and accessing properties.

Memory management technique for Objective-C iVars/properties

Is the following code doing anything unnecessary?
#interface MyClass {
NSArray *myArray;
}
-(void)replaceArray:(NSArray *)newArray;
#implementation MyClass
-(void)replaceArray:(NSArray *)newArray {
if( myArray )
{
[myArray release];
myArray = nil;
}
myArray = [[NSArray alloc] initWithArray: newArray];
}
#end
What if I made the following changes:
1) Made myArray a property:
#property (nonatomic, retain) NSArray myArray;
2) Changed the assignment to:
self.myArray = [NSArray arrayWithArray: newArray];
Would that allow me to remove the conditional?
You don't need the conditional at all; you can message nil (including a release), and nothing will happen. You also don't need to allocate a new array; you can retain the one passed to you instead. If you're worried about actually getting an NSMutableArray, you can make a copy. I'd do this:
- (void)replaceArray:(NSArray *)newArray
{
[myArray autorelease];
myArray = [newArray copy];
}
Or, if you don't want to use autorelease, you could do:
- (void)replaceArray:(NSArray *)newArray
{
if (myArray != newArray) {
[myArray release];
myArray = [newArray copy];
}
}
You can already get rid of the conditional. If the array is nil, then you'll be sending a message to nil, which is a no-op. The assignment to nil is pointless either way as well. And if you make it a retain property, explicitly releasing the old value is wrong.
However, there is one case where that code will not work correctly: When the argument is the current value. In that case, you'll release the current value and then try to use the released object (which may already have been dealloced) to create a new array.
Imaging the following:
MyClass * myObj;
// init myObj
NSArray * array = [myObj myArray];
[myObj replaceArray:array];
In this case, myArray and newArray are the same, which means you're using it after it being released. To solve this problem, all you need to do is remove the replaceArray: method, and implement the property as #synthesize myArray. So the above code changes to
MyClass * myObj;
// init myObj
NSArray * array = [myObj myArray];
[myObj setMyArray:array];
and your problem is solved by the synthesized implementation.
Note that you are setting your value by creating a new array:
myArray = [[NSArray alloc] initWithArray: newArray];
if this is the behaviour you want, you should change your property definition to copy instead of retain:
#property (nonatomic, copy) NSArray myArray;
I've voted up mipadi because his answer is right in the context of the question you asked, but why not just use a property and do away with replaceArray: altogether:
#interface MyClass {
NSArray *myArray;
}
#property (copy) NSArray* myArray;
#end
#implementation MyClass
#synthesize myArray;
-(void) dealloc
{
[myArray release];
[super dealloc];
}
#end

'initializing' a property which is retained

In the iPhone objective-c world, I've seen this pattern everywhere and I use it myself all the time without really understanding what is going on:
In Test.h
#interface Test: UIViewController
{
NSMutableArray *testArray;
}
#property (retain, nonatomic) NSMutableArray *testArray;
And in Test.m
#implementation Test
#synthesize testArray
- (void) viewDidLoad
{
// why do we do this?
NSMutableArray *init = [[NSMutableArray alloc] init];
self.testArray = init;
[init release];
[self.testArray addObject: #"A"]; // why can't I do this directly?
...
}
- (void) dealloc
{
[testArray release];
[super dealloc];
}
My question is: if testArray has a retain on it when it's declared in the property, why do we need to create a new NSMutableArray init object, assign that to testArray and release? Why can't I just start using testArray in viewDidLoad without doing anything else?
I know there's some debate over the best way of doing this (creating a new object, or using an autorelease object), but in both cases, we end up with testArray with a retain count of 1. Which I believe the 'retain' property already gives it. So why the need to create this init object?
The 'retain' property doesn't automatically create an NSMutableArray for you. Rather, it simply indicates that whenever you do assign something to that property, it will be retained.
If your code were this:
- (void) viewDidLoad
{
[self.testArray addObject: #"A"];
}
Then self.testArray would be nil, and thus it would be essentially a no-op. Until you assign something to self.testArray, it's empty.
Here's what's going on.
- (void) viewDidLoad
{
// we need to assign an NSMutableArray to self.testArray.
NSMutableArray *init = [[NSMutableArray alloc] init];
// The array has been retained once (by the call to |alloc|)
self.testArray = init;
// The array is assigned to a property with the 'retain' attribute
// Thus, the array has now been retained twice
[init release];
// We release the array, so it now is retained once.
// We now have an array in self.testArray, so we can add something to it.
[self.testArray addObject: #"A"];
}
The "retain" in the #property directive specifies that the setter should retain the input value instead of simply copying the value. It has nothing to do with allocating (setting aside memory) and initializing (constructing the object) the object. retain on the #property directive simply increments the retain count when the setter is called (which alllows you to do something like self.myobject = something without specifically calling retain.