Как я могу реализовать такое же поведение, как в шаблоне кластера от Apple (NSString и NSCFString)

Я просто пишу следующий код для тестирования:

NSString *aStr = [[NSString alloc] initWithFormat:@"Foo"];
aStr = [aStr initWithFormat:@"Bar"];//Crashed here

Я получаю следующую ошибку:

*** initialization method -initWithFormat:locale:arguments: cannot be sent to an abstract object of class __NSCFString: Create a concrete instance!

Если я напишу следующий код, то же самое произойдет

NSString *aStr = [NSString alloc];
aStr = [aStr initWithFormat:@"Foo"];
aStr = [aStr initWithFormat:@"Bar"]; //Crashed here

По Google я узнал, что initWithFormat вернет NSCFString Объект. Мой вопрос, если NSCFString является производным классом NSString тогда почему я не могу ссылаться на initWithFormat метод на NSCFString, Если возможно остановить видимость, как я могу реализовать в коде, не переопределяя метод в NSCFString(Производный класс).

Проще говоря, если NSCFString является производным классом NSString, то почему я не могу вызвать метод базового класса (initWithFormat) для этого?

3 ответа

Я считаю, что происходит то, что [NSString initWithFormat:] метод замечает, что вы не предоставили никаких спецификаторов формата, поэтому нет NSString объект, который нужно построить, поэтому он просто возвращает константу NSString объект, который вы передаете (@"Foo"):

NSString *aStr = [NSString alloc];
aStr = [aStr initWithFormat:@"Foo"];

Так aStr сейчас типа NSCFString, Это причина сбоя:

aStr = [aStr initWithFormat:@"Bar"]; //Crashed here

Однако вы никогда не должны звонить init метод для существующего объекта, поэтому для исправления сбоя используйте:

aStr = [[NSString alloc] initWithFormat:@"Bar"];

и используйте спецификаторы формата, как вы можете просто:

aStr = @"Foo";
aStr = @"Boo";

это то же самое, только яснее, использует меньше кода и имеет лучшую производительность.

Вы спрашиваете "почему". Помимо ответа "дважды вызывать init для одного и того же объекта - baaaad", который вы проигнорировали, NSString является кластером классов.

[NSString alloc] возвращает универсальный объект, который на самом деле нельзя использовать в виде строки, но ожидает вызова метода init. Давайте подумаем о чем-то очевидном: объекты NSString являются неизменяемыми, но результат [NSString alloc] не может быть неизменным, потому что в противном случае было бы невозможно сохранить значение, верно?

Этот метод init фактически возвращает другой объект, который больше не принимает методы init. Хотя [NSString alloc] является очень гибким объектом, который может делать все что угодно, после вызова метода init вы получаете объект, который содержит строку, которая никогда не может быть изменена снова.

(Apple, возможно, реализовала это не так, как я говорю, или может изменить их реализацию. Тем не менее, они могут и будут делать вещи, которые мешают вам делать глупости).

И предупреждение: даже не думайте о создании подкласса NSString. Я могу гарантировать, что вы не получите ничего, что работает вместе.

Согласно документации он возвращает NSString объект инициализируется с использованием заданной строки формата в качестве шаблона, в который подставляются остальные значения аргумента.

А также вам нужно использовать, как показано ниже:

NSString *aStr = [[NSString alloc] initWithFormat:@"%@,%@",@"Foo",@"Bar"];
NSLog(@"%@",aStr);
Другие вопросы по тегам