Problems using NSMutableArray - objective-c

I have created an object of type NSMutableArray
#import <Foundation/Foundation.h>
#interface MyCustomObject : NSMutableArray
{
}
#end
in one of my classes, I delcare an instance:
MyCustomObject *myObj = [[NSMutableArray alloc] init];
But xcode is giving a warning on this line:
Incompatible pointer types initializing 'MyCustomObject *' with an expression of type 'NSMutableArray *'
Any idea what is wrong? It works fine, but just wondering why it is throwing a warning and how to resolve it?

You can assign a child class to a variable typed as its super-class, but you cannot assign a super-class to a child class variable.
So, you'd want to:
MyCustomObject *myObj = [[MyCustomObject alloc] init];

Firstly, as everyone else has said, you need to instantiate your class if you want an instance of your class. Evidently the reason you're not doing this is because you tried instantiating your class and it didn't work. That's the deeper problem: You can't simply subclass NSArray or NSMutableArray. As noted in the documentation, NSArray is a class cluster, which is basically a short way of saying "NSArray doesn't actually implement most of its methods."
In order to subclass NSArray, you essentially have to provide all of its functionality yourself. It is generally much easier to either create a category on NSArray or create a custom class that has an array as a member.

I think you've got things backwards. MyCustomObject is a NSMutableArray, but NSMutableArray isn't a MyCustomObject. Your variable myObj should be a NSMutableArray if it needs to be able to hold both NSMutableArrays and MyCustomObjects.

You should be instantiating the object as:
MyCustomObject *myObj = [[MyCustomObject alloc] init];
Otherwise, all you're doing is making an NSMutableArray and don't need your custom object (since none of its functionality would work.)

It should be:
MyCustomObject *myObj = [[MyCustomObject alloc] init];
if you do:
NSMutableArray *myObj = [[MyCustomObject alloc] init];
It will create an istance of MyCustomObject, but you will have a NSMutableArray pointer, so your new instance will just be seen as a NSMutableArray.
In this case:
MyCustomObject *myObj = [[NSMutableArray alloc] init];
It is an error. In previows a MyCustomObject can ben seen as a simple NSMutableArray. but a NSMutableArray cannot ever be seen as a MyCustomObject. It is a simple inheritance property.
Maybe this can help
http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming

Try allocating a MyCustomObject instead:
MyCustomObject *myObj = [[MyCustomObject alloc] init];

Related

NSArray only changed if class is passed

I have a class with a NSArray property using ARC with nothing fancy...
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
property(nonatomic, strong) (NSArray *) myArray;
#end
#import "MyClass.h"
#implementation MyClass
#synthesize myArray = _myArray;
#end
If an attempt is made to use a method inside of another class to try to set that array it does not set it if only the array is passed; however, it does set if the class is passed, I'm not sure why that is....
The code that attempts this both ways is below...
MyClass *myClass = [[MyClass alloc] init];
[self setArrayByPassingArray:myClass.myArray];
NSLog (#"%#", myClass.myArray)
//result is null
[self setArrayByPassingClass:myClass];
NSLog (#"%#", myClass.myArray)
//result is test, test2...
-(void)setArrayByPassingArray:(NSArray *)arrayToSet {
arrrayToSet = [[NSArray alloc] initWithObjects: #"test", #"test2", nil];
}
-(void)setArrayByPassingClass:(MyClass *)classWithArrayToSet {
classWithArrayToSet.myArray = = [[NSArray alloc] initWithObjects: #"test", #"test2", nil];
}
I tried some other methods with just strings and the strings are not changed, so I'm not sure why they are changed if class containing them is passed...
Your setArrayByPassingArray: method in the first example assigns the newly created NSArray to its parameter, which is passed by value, and is promptly discarded upon exiting from the method. What happens here is that a copy of the reference to myArray is made (not a copy of the array, only a copy of a reference to that array) before calling setArrayByPassingArray:. That copy is no longer attached to the myArray member of MyClass.
Your second example is not passing a class - it's passing an instance of the class, and then it correctly uses the dot notation to assign the myArray property in your instance. That's why this second example works, and the first example does not.
If you use NSMutableArray instead of NSArray throughout your program, you can rewrite your first example to make it work:
-(void)setArrayByPassingArray:(NSMutableArray *)arrayToSet {
[arrrayToSet setArray:[[NSArray alloc] initWithObjects: #"test", #"test2", nil]];
}

ios initialize an instance inside a function to use outside

the xcode analyzer tell me that a method returns an Objective-C object with a +1 retain count:
but the self.athletes is an object that I need also outside my function... how can I solve this 'warning?
thanks again
the athletes is declared like this:
NSMutableArray *athletes;
#property (nonatomic, retain) IBOutlet NSMutableArray *athletes;
Replace that line with this one:
self.athletes = [NSMutableArray array];
I wrote full explanation here : Memory Management for properties with retain attribute
Since your property is defined with "retain", using the dot notation will result in an extra retain. The return from the [[NSMutableArray alloc] init] has a retain count of 1, and then when you set the property using the setter function generated by the property declaration it will have a retain count of 2.
To fix, either:
self.athletes = [NSMutableArray array]; // Returns an autoreleased object
Or, you could also do this:
athletes = [[NSMutableArray alloc] init]; // Doesn't use the setter generated by the property declaration, so doesn't retain again.
There is a nice way to handle this (and you have already used this pattern while creating UI ).
NSMutableArray *athletesTemp = [[NSMutableArray alloc] init];
self.athletes = athletesTemp;
[athletesTemp release];
Here you don't need to carry the load of an auto release object.

Question about release the object

I have a class which contain a NSArray object.
like this
#import <Foundation/Foundation.h>
#interface myClass : NSObject {
NSArray *myArray;
}
#property (nonatomic, retain) NSArray *myArray;
#end
In .m file, I init myArray in init method,and release myArray in dealloc method.
in a method, I create its object and add it to a NSMutableArray.
myClass *my = [[myClass alloc] init];
NSLog(#"init finish %d",[my retainCount]);
NSMutableArray *a = [[NSMutableArray alloc] init];
[a addObject:my];
NSLog(#"array added finish %d",[my retainCount]);
NSLog(#"array added finish %d",[my.myArray retainCount]);
[my release];
When i add object "my" to NSMutableArray, the retainCount of "my" was added.
but myArray wasn't. Did it mean that I must retain myArray by my self?
or something other I can do.
Can this code work normal after I release "my" object?
[a objectAtIndex:0];
Thanks!
Another great example of exactly why you should...
NEVER call -retainCount!
retainCount is useless, misleading and a waste of your time.
In this case, the reason why the retain count happens to be zero "unexpectedly" is because my.myArray returns nil. That happens because you never assign the created mutable array to myArray.
You need something like this (Class name capitalized to follow convention):
MyClass *my = [[MyClass alloc] init];
NSMutableArray *a = [[NSMutableArray alloc] init];
my.myArray = a;
[a addObject:my];
Note that this creates a retain cycle between my and the array. I.e. you will need to remove my from the array manually (or remove the array from my manually) whenever you release myArray and, of course, you can't do that in dealloc because dealloc will never be called until my has been removed from myArray.
I am not sure if that is the full source code above but for my.myArray to be retained you have to actually assign something to it.
So in your above example you created an NSMutableArray:
NSMutableArray *a = [[NSMutableArray alloc] init];
And then you added your class to it:
[a addObject:my];
But no where have you created an array and assigned it to myClass as in:
NSArray *anArray = [[NSArray alloc] init.....];
my.myArray = anArray;
At that point, myArray will get a reference to an object and will retain it (since you specified retain in your myArray prop declaration).
Perhaps if you clarified what it is you are trying to do or posted some more full source code?

How do I initialize an instance variable when the object is created in Objective C?

In C++ I would do this in the constructor, but on Objective C I do not know how I am supposed to initialize it.
For example I have a member variable that has to be a dictionary and I want to initialize this dictionary.
When you say initialize the dictionary, I am assuming you just want to allocate memory for it. If so you can do the following sample:
- (id) init {
self = [super init];
if (self != nil) {
_privateDict = [[NSMutableDictionary alloc] initWithCapacity:40];
}
return self;
}
Generally, you use the init method. For example:
Myclass *anInstance = [[MyClass alloc] init];
Some classes have specialized initializers that will take parameters. A classic example is any UIViewController subclass that you implement. Does this look familiar?
MyUIViewController *viewController = [[MyUIViewController alloc] initWithNibNamed: #"MyUIViewController" bundle: nil];
Notice the initWithNibNamed bit. You can write custom initializer like that as well. I suggest reading code that others wrote. Look for the initializer and try to understand how it was written/"set up".
To make a dictionary, you can use NSDictionary or NSMutableDictionary. Those have several initializers. You can use initWithObjects: and then pass in a bunch of objects to store in the dictionary.
You should read - The Objective-C Programming Language: Allocating and Initializing Objects

Why or why not call an object with a "self." prefix?

#interface{
NSArray *array;
}
#property (nonatomic, retain) NSArray *array;
#end
#implementation
#synthesize array;
self.array = [[NSArray alloc] init];
array = [[NSArray alloc] init];
[self.array objectAtIndex:2]; [array objectAtIndex:2];
#end
Is there a difference between them? Why should I use one over the other?
self.array = foo is shorthand for [self setArray:foo] (i.e. you access the synthesized property methods), while just array = foo directly accesses the instance variable.
In exactly this case, you would create a memory leak with self.array = [[NSArray alloc] init]; since the property will retain it and the reference count would thus be 2 instead of 1. So better would be: self.array = [NSArray array];.
Which one to prefer is almost a matter of taste, but using the properties gives you a few advantages like automatic key-value coding support. It's also an advantage if you someday chose to do implement setArray: yourself so it can do additional stuff when the array is assigned (like reloading a UITableView). On the other hand, it's a little bit slower as it's an additional method call (only matters if called in a loop a lot). But for almost all applications it's better to be correct than as fast as possible. Using properties can make memory management easier for you.
The property "array" is declared to retain on assignment (the retain in the brackets after #property signifies this). Because it has the same name as the "array" instance variable it uses that instance variable as it's backing store.
Effectively calling self.array = [[NSArray alloc] init]; is the same as calling array = [[[NSArray alloc] init] retain];
When you assign to the instance variable directly, not using the property, no action is taken on it, so array simply points to a new instance of NSArray without retaining it.