Как инициализировать NSMutableArray в Objective C?

Я исхожу из фона Java, и я изучаю Objective C. Я пытаюсь создать класс, который имеет строковый массив и функцию-член для изменения массива. Мой код выглядел так:

@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

Что не сработало. Я получил "[__NSArrayI addObject:]: unrecognized selector sent to instance " и "NSInvalidArgumentException". После поиска в Интернете я сменил одну строчку в конструкторе на:

self.mItems = [self.mItems init];

Это сработало, но почему? С точки зрения разработчика Java первый имеет больше смысла, чем второй. И у меня есть другая строка, такая же, как и первая, но она работает (не в конструкторе). Может кто-нибудь объяснить это мне, пожалуйста?

Ответ 1

  • Прежде всего, вы должны придерживаться условных обозначений Objective-C. В Objective-C классы не имеют конструкторов, у них есть инициализаторы. В Objective-C инициализаторы вызывают инициализатор суперкласса, поэтому он должен выглядеть следующим образом:

    - init
    {
        self = [super init];
        if (!self) return nil;
    
        // set up other stuff here 
    
        return self;
    }
    
  • Во-вторых, если вы не используете ARC, у вас может быть утечка памяти. В первой строке вашего инициализатора присваивается объект, которому вы владеете, свойство, которое также, вероятно, переходит в собственность. Вы должны использовать либо:

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

    или

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

    Apple иногда обескураживает использование методов доступа в инициализаторах, потому что может играть с такими вещами, как KVO, но последовательное использование методов доступа обеспечивает правильное владение объектами и управление памятью.

  • Изменив строку в своем инициализаторе на:

    self.mItems = [self.mItems init];
    

    делает ничего. Когда вы вызываете свой метод инициализации (как правило, сразу после его выделения), все переменные экземпляра автоматически устанавливаются на нуль. Итак, что вы делаете, просто:

    self.mItems = [nil init];
    

    который справедлив:

    self.mItems = nil;
    

    и не используйте init без предварительного выделения экземпляра и никогда не используйте init более одного раза.

  • Если вы не позволяете инициализировать суперкласс, он может проявляться как проблемы в других областях. Сделайте Сборка и анализ и убедитесь, что вы устранили все проблемы, на которые указывает анализатор.

Ответ 2

Так как objective-c является надмножеством c, в основном c с некоторым синтаксическим сахаром "OO". Прежде чем вы сможете создать (или использовать!) Объект, вы должны выделить место для него в куче. вы делаете это с помощью [Class alloc]. Следующим шагом будет инициализация этого пространства. alloc возвращает указатель на это пространство в куче, которое вы инициализируете с помощью init;)

Итак, вы вызываете Class *myObjc = [[Class alloc] init];.

Если вы используете наследование (которое вы делаете с момента наследования из NSOBject), вы должны убедиться, что ваш суперкласс правильно инициализирован, т.е. вызов super. Чтобы убедиться, что вы не получите ошибку времени выполнения, проверьте self!= Nil, который вы неявно используете с 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. 

используйте этот код:

@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

Вы должны вызвать super и назначить его результат self в вашем методе init:

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

Ответ 4

Другим способом может быть создание NSMutableArray из NSArray:

NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];