problem related to NSString - iphone

I have 1 NSString *abc = #"Hardik";
i have NSMutableArray *array;
now i had written [array addobject:abc];
then i'm printing,NSLog(#"array = %#", array);
but i'm getting NULL
why?
I have declared NSMutableArray *array; in a.h file
i had set #property(nonatomic,retain)NSMutableArray *array;
#synthesize array;
and i have synthesize it but getting value NULL
I'm not able to understand it?

You also need to initialise your array:
array = [[NSMutableArray alloc] initWithCapacity:10];
This is pretty fundamental stuff. Have you read the "Learning Objective C Primer" yet?

It sounds like you haven't actually allocated array. Generally, you would do this in your initializer. (Don't forget to add a release to your dealloc method, too.) #synthesize creates the getter and setter, but you still have to handle allocating/deallocating the object yourself.

It sounds like your NSMutableArray* array property may not have been initialised?
Can you post your class init method?

To trigger the synthesized accessor within a class itself, you must use self. If you don't, you access the attribute's address directly bypassing the accessor methods. You need:
NSString *abc = #"Hardik";
[self.array addobject:abc];
NSLog(#"array = %#", self.array);
The reason this is important is that the synthesized methods usually also initialize the property. The internals of the synthesize array method would look something like:
-(NSArray *) array{
if (array!=nil) {
return array;
}
array=[[NSMutableArray alloc] initWithCapacity:1];
return array;
}
self.propertyName is really just shorthand for [self propertyName] and self.propertyName=someValue is just shorthand for [self setPropertyName:someValue].
Until you call self.array at least once, the array property is not initialized.
However, just to confuse things, once you have called self.array once it is initialized so you can just call array directly. So...
[self.array addObject:abc];
NSLog(#"array = %#", array);
...works while the converse would return just an empty array.
So the rules are:
Within a class implementation
(including subclasses), calling just
propertyName gives you the address
of the property but does not call
the getter/setter accessor methods.
Within a class implementation
(including subclasses), using
self.propertyName calls the
getter/setter accessor methods but
does not access attribute directly.
From outside the class
implementation e.g.
myClass.propertyName calls the
getter/setter accessor methods.

Related

Self with an array and addObject

When inserting an object into an array with a property is there any reason to invoke the getter/setter with self? i.e.
[self.myArray insertObject: myObject];
Or can I just use:
[myArray insertObject: myObject];
the gist would be:
.h
#interface ArrayViewController : UIViewController <UITextFieldDelegate>
{
NSMutableArray *myArray;
int itemNumber;
}
#property (nonatomic, retain) NSMutableArray *myArray;
#end
.m
- (IBAction)createMyArray
{
self.myArray = [[NSMutableArray alloc] initWithObjects: nil];
}
-(IBAction) addItemToMyArray
{
NSString *myString = [[NSString alloc] initWithFormat:#"item %d",itemNumber];
[myArray addObject: myString];
//[self.myArray addObject: myString]; //Or should I use self?
[myString release];
NSLog(#"myArray = %#", myArray);
itemNumber++;
}
//- (void)dealloc etc. not shown
Conceptually, it doesn't matter, so long as your getter method only returns the existing field value and doesn't, eg, do some "just in time" allocation or some such.
However, it's good practice to come up with a policy (personal or group) that you stick with, so that the caveats of that policy become second nature. Constantly switching styles results in sloppy, buggy code.
I tend to always use the self. for properties, just to remind myself that they are, in fact, properties, and to make it less likely that I'll accidentally set the value without using the property notation.
Either will work but you need to be aware of what you are doing. Using self. will invoke the setter/getter methods while the other will just access the variable directly. Using the variable directly, while perfectly valid, is discouraged outside of the initializer and dealloc method. The reason is you are losing out on the benefits of the property, especially setting using self. because it will properly assign/copy/retain the value for you correctly. Another reason not use property variables directly is because of atomicity but in your case you declared it as nonatomic.
Both of those are fine. It's mostly a stylistic choice. Using self.myArray will result in a call to the getter [self myArray].
When using alloc/init you should not set the returned value to a property, as these will retain twice:
self.myArray = [[NSMutableArray alloc] initWithObjects: nil];
use
myArray = [[NSMutableArray alloc] initWithObjects: nil];
or
self.myArray = [NSMutableArray array];
for the initialization.
The insert operations are equivalent though.
I typically skip the getter because I rarely find it valuable and it clutters up the readability of the code a bit. However, I tend to use the setter because I find it easier to allow the auto-generated setter methods to handle the retain/release semantics
In your case it's not an obligation to use self.myArray but for this case belloaw it will be an obligation:
-(void) addItemToMyArray:(NSAarray *)myArray
{
NSString *myString = [[NSString alloc] initWithFormat:#"item %d",itemNumber];
[self.myArray addObject: myString];
[myString release];
NSLog(#"myArray = %#", self.myArray);
itemNumber++;
}
to difference between the class attribut and the function argument.

How do I removeAllObjects on my NSMutableArray that is part of another object?

I have an object defined like this:
Scores.h:
#interface Scores : NSObject {
NSString *sentenceKey;
NSMutableArray *scorrectAnswers;
}
#property (nonatomic, copy) NSString *sentenceKey;
#property (nonatomic, copy) NSMutableArray *scorrectAnswers;
+ (id)addScore:(NSString *)senKey;
- (id)initWithSentenceKey:(NSString *)sKey
scorrectAnswers:(NSMutableArray *)scorrectAs;
- (id)initWithSentenceKey:(NSString *)sKey;
- (void)removeArrayObjects;
Score.m:
#import "Scores.h"
#implementation Scores
#synthesize sentenceKey, scorrectAnswers;
+ (id)addScore:(NSString *)senKey
{
Scores *newScore = [[self alloc] initWithSentenceKey:senKey
scorrectAnswers:[NSMutableArray new]];
return [newScore autorelease];}
I'm trying to removeAllObjects on my mutable array with this method:
- (void)removeArrayObjects;{
[scorrectAnswers removeAllObjects];}
...which I call from another program like this:
for (Scores *sScore in scores)
{
[sScore removeArrayObjects];
}
... and I get this error when I run it:
-[__NSArrayI removeAllObjects]: unrecognized selector sent to instance 0x53412d0
Can anyone tell me what I'm doing wrong here? Thanks.
You are not dealing with an NSMutableArray as the error indicates you have an immutable NSArray.
This question may be your answer NSMutableArray addObject: -[__NSArrayI addObject:]: unrecognized selector sent to instance
Basically the copy you used when defining your #property will cause the setter to be generated using
scorrectAnswers = [newMutableArray copy];
which returns an immutable NSArray.
You can re-implement this method and change the previous line for:
scorrectAnswers = [newMutableArray mutableCopy];
or use retain instead of copy
This can also occur when getting data from a plist
If you are using a plist it will return an NSArray even if you save an NSMutableArray it will be cast. So when retrieving you will need to do something like:
scorrectAnswers = [[NSMutableArray alloc] initWithArray:[userDefault objectForKey:#"my_array_key"]]
It doesn't look like like the memory pointed to by scorrectAnswers is actually pointing to an NSMutableArray. Where and how do you initialize that variable? If you are setting the ivar directly with an autoreleased object, like:
scorrectAnswers = [NSMutableArray arrayWithCapacity:10];
then the autoreleased array will be destroyed, since you're not retaining it (or copying it). If that memory gets reallocated to point to another object, you'll see an error like the one you're getting, with an unexpected type. If the memory has not been reallocated, you'll get an EXC_BAD_ACCESS error.
Similar to what was mentioned above, I had an NSMutableArray which was being re-allocated somewhere in my code as an NSArray. Once I modified that to correctly be an NSMutableArray, it resolved my problem.
I would suggest doing a quick search to ensure that you have not reallocated the array somewhere in your project and modify accordingly.

NSNumber's copy is not allocating new memory

I am implementing a copyWithZone method for a custom A class, in which a NSNumber pointer was declared as (retain) property
#class A <NSCopying>
{
NSNumber *num;
}
#property (nonatomic, retain) NSNumber *num; // synthesized in .m file
-(id) copyWithZone:(NSZone*) zone {
A *new = [[A alloc] init];
new.num = [num copy];
return new;
}
When I debug, I always find new.num is the same address as the self.num.
Even if I use
new.num = [NSNumber numberWithFloat: [num floatValue]];
I still get the same address. In the end, I have to use
new.num = [[[NSNumber alloc] initWithFloat:[num floatValue]] autorelease]
to achieve the result I want. I am just wondering why NSNumber complies to but does not return a new memory address when copied?
Thanks
Leo
NSNumber is immutable. Making a copy is pointless and, thus, the frameworks just return self when copy is invoked.
If a class implements NSCopying, you should mark the property as copy (not retain). -copy on immutable classes (NSString) will simply return a reference to the object (w/a bumped retain count). If passed a mutable instance, it'll be copied to an immutable instance. This prevents an external party from changing the state behind your object's back.
Not only is NSNumber immutable - for low values it as also a Flyweight.
NSNumber isn't mutable, so there is no need to force physical copying.
You should be using [[A alloc] initWithZone:zone] when implementing the NSCopying protocol.
As others have stated though, NSNumber is immutable and so returns the same object.

iPhone memory management (with specific examples/questions)

Hey all. I know this question's been asked but I still don't have a clear picture of memory management in Objective-C. I feel like I have a pretty good grasp of it, but I'd still like some correct answers for the following code. I have a series of examples that I'd love for someone(s) to clarify.
Setting a value for an instance variable:
Say I have an NSMutableArray variable. In my class, when I initialize it, do I need to call a retain on it?
Do I do
fooArray = [[[NSMutableArray alloc] init] retain];
or
fooArray = [[NSMutableArray alloc] init];
Does doing [[NSMutableArray alloc] init] already set the retain count to 1, so I wouldn't need to call retain on it? On the other hand, if I called a method that I know returns an autoreleased object, I would for sure have to call retain on it, right? Like so:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
Properties:
I ask about the retain because I'm a bit confused about how #property's automatic setter works.
If I had set fooArray to be a #property with retain set, Objective-C will automatically create the following setter, right?
- (void)setFooArray:(NSMutableArray *)anArray {
[fooArray release];
fooArray = [anArray retain];
}
So, if I had code like this: self.fooArray = [[NSMutableArray alloc] init]; (which I believe is valid code), Objective-C creates a setter method that calls retain on the value assigned to fooArray. In this case, will the retain count actually be 2?
Correct way of setting a value of a property:
I know there are questions on this and (possibly) debates, but which is the right way to set a #property?
This?
self.fooArray = [[NSMutableArray alloc] init];
Or this?
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
I'd love to get some clarification on these examples. Thanks!
According to Apple's Object Ownership Policy, any method that begins with the words alloc or new, or contains copy is owned by the caller.
To obtain ownership of an object, you must retain it.
So, in your first example, the retain is unnecessary because you already own the object.
The correct way to do this:
fooArray = [[NSMutableArray alloc] init];
Since autoreleased objects are owned by the current autorelease pool, you must call retain on them to gain ownership of them, so this example is correct:
fooString = [[NSString stringWithFormat:#"%d items", someInt] retain];
This would work fine as well:
self.fooString = [NSString stringWithFormat:#"%d items", someInt]; //retained by property setter
And for your last example using the property setter, this would be the correct way to do it:
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
Instead of having to do the above, I'd suggest the following solution:
self.fooArray = [NSMutableArray arrayWithCapacity:10];
arrayWithCapacity: will return an autoreleased NSMutableArray, which is the retain-ed by the property setter method. :)
Ideally you would want to use the accessors whenever possible, especially when dealing with objects as they help avoid many memory issues. So even for instance variables, you should do:
self.fooArray = ...;
instead of
fooArray = ...;
The reason why you should declare properties for object instance variables is because the memory management is slightly more complicated, and recreating it by hand each time is tricky. The correct setter for a nonatomic, retained property would look like:
- (void)setFoo:(NSArray *)aFoo {
if (foo == aFoo) {
return;
}
NSArray *oldFoo = foo;
foo = [aFoo retain];
[oldFoo release];
}
You are right about the instance variable having a retain count of 2 when you do something like this (assuming foo is retained):
self.foo = [[NSMutableArray alloc] init];
The first retain count is coming from alloc, and the second one from your synthesized setter. Any of these should work:
// longer, explicit version, releases immediately (more efficient)
NSMutableArray *aFoo = [[NSMutableArray alloc] init];
self.foo = aFoo;
[aFoo release];
// autoreleased, not so bad unless you're a memory management freak
self.foo = [[[NSMutableArray alloc] init] autorelease];
// an even shorter version of the above
self.foo = [NSMutableArray array];
To create private properties, you can declare them as a class extension in the .m implementation file. To give an example, consider a simple Person object, which has a name, and a boolean property didSave which simply indicates whether the object has been saved to some database or not. Since we don't want to expose this to the outside world, but still keep the benefits of properties inside the implementation file, we can create the header file will all instance variables (public, private, protected) and only public properties:
// Person.h
#interface Person {
NSString *name;
#private
BOOL didSave;
}
#property (nonatomic, retain) NSString *name;
#end
But declare private properties inside the implementation:
// Person.m
// property is declared as a class extension, making it
// invisible to the outside world.
#interface Person ()
#property BOOL didSave;
#end
#implementation
// synthesize as normal
#synthesize name, didSave;
#end
First of all, with this line:
fooArray = [[NSMutableArray alloc] init];
fooArray will automatically have a retain count of 1.
Second, yes, it's 2. And your guess on the setter implementation is correct.
Third, the latter one is right

Why should I use KVC rather than the simple dot syntax when accessing object properties?

There's the option to go the long way, if an receiver class conforms to the NSKeyValueProtocol:
[myInstance setValue:[NSNumber numberWithInt:2] forKey:#"integerProperty"];
or the short way:
myInstance.integerProperty = 2;
what's the point of this KVC method? When is this useful?
First, those aren't the same, the second should be:
myInstance.integerProperty = [NSNumber numbwerWithInt:2];
if integerProperty is an NSNumber.
In general you use the second form when you are doing the most things. You use setValue:forKey: and valueForKey: when you want to dynamically choose the property to store things in. For instance, think about how valueForKeyPath: against an NSArray works (for reference, if you call -valueForKey: against an NSArray it will return an array where each object is the result of asking the corresponding object in that NSArray for that value:
- (NSArray *) valueForKey:(id)key {
NSMutableArray *retval = [NSMutableArray array];
for (NSObject *object in self) {
[retval addObject:[object valueForKey:key]];
}
return retval;
}
In the above case we were able to use valueForKey: to implement our function even though we do not know what the key is beforehand, since it is passed in as an argument.