How to initialize a NSMutableArray in Objective C?

2019-04-05 00:36发布

问题:

I come from a Java background and I am learning Objective C. I am trying to create a class that has a string array and a member function to modify the Array. My code looked like this:

@implementation TAWChapter

@synthesize mSubject;

@synthesize mItems;

- (id) init{
    self.mItems = [[NSMutableArray alloc] init];
    return self; 
}

- (void) setSubject:(NSString *)subject{
    self.mSubject = subject; 
}

- (void) addItem:(NSString *)item{
    [self.mItems addObject:@"asdf"]; 
}

@end

Which didn't work. I got a "[__NSArrayI addObject:]: unrecognized selector sent to instance " and a "NSInvalidArgumentException". After searching on internet, I changed the single line in the constructor to:

self.mItems = [self.mItems init];

It worked, but why? From a Java developer's point of view the first one makes more sense than the second one. And I have another line it's the same as the first one but it's working(not in a constructor). Can someone explain this to me please?

回答1:

  1. First of all, you should adhere to Objective-C coding conventions. In Objective-C, classes don't have constructors, they have initialisers. In Objective-C, initialisers invoke the initialiser of the superclass, so it should look like this:

    - init
    {
        self = [super init];
        if (!self) return nil;
    
        // set up other stuff here 
    
        return self;
    }
    
  2. Second, unless you are using ARC, you might have a memory leak. The first line of your initialiser assigns an object that you own to a property that also likely takes ownership. You should use either:

    // property takes care of ownership
    self.mItems = [NSMutableArray array];
    

    or:

    // assign to instance variable directly with owned object
    mItems = [[NSMutableArray alloc] init];
    

    Apple sometimes discourage the use of accessor methods in initialisers because it can fiddle with things like KVO, but consistent use of accessor methods ensures proper object ownership and memory management.

  3. By changing your line in your initialiser to:

    self.mItems = [self.mItems init];
    

    does nothing. When your initialiser method is called (which is typically just after it has been allocated), all instance variables are automatically set to nil. So what you are doing is just:

    self.mItems = [nil init];
    

    which is just:

    self.mItems = nil;
    

    and, don't use init without first allocating an instance, and never use init more than once.

  4. If you do not let the superclass initialise itself, then it may manifest as problems in other areas. Do a Build & Analyze and ensure you have fixed up any issues pointed out by the analyser.



回答2:

Since objective-c is a superset of c, it's basically c with some "OO" syntax sugar. Before you can create (or use!) an object, you must alloc space for it in the heap. you do this with [Class alloc]. The next step is the initialization of that space. alloc returns a pointer to that space in the heap, which you initialize with init ;)

So you call Class *myObjc = [[Class alloc] init];.

If you use inheritance (which you do since you inherit from NSOBject), you must make sure that your superclass initialized everything properly, thats the call to super. To make sure you don't get a runtime error, check for self != nil, which you do implicitly with if(self)

self.mItems = [self.mItems init]; // doesn't do anything, since you call the getter for mItems with self.mItems and try to init. then you try to set mItmes to itself. 

use this code:

@implementation TAWChapter

@synthesize mSubject, mItems;

- (id)init
{
    self = [super init];
    if (self) {
        mItems = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void) setSubject:(NSString *)subject{
    mSubject = subject; 
}

- (void) addItem:(NSString *)item{
    [mItems addObject:item]; 
}

@end


回答3:

You should call super and assign its result to self in your init method:

- (id)init
{
    self = [super init];
    if (self) {
        self.mItems = [[NSMutableArray alloc] init];
    }
    return self;
}


回答4:

The another way could be creating NSMutableArray from NSArray:

NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];