Objective C, что именно делает [NSString initWithFormat]?

Я просто хотел бы знать разницу между строками 1 и 2 ниже:

_subtitle = @"Test"; //Line 1
_subtitle = [NSString stringWithFormat: @"Test"]; //Line 2

Если я задал этот вопрос, то это потому, что у меня возникла проблема с использованием MKAnnotation. В приведенном ниже методе я пытаюсь обновить свойство делегата субтитров MKAnnotation (которое является неатомарным, копируемым и доступным только для чтения). Но похоже, что я получил зомби при использовании строки 2 и ничего при использовании строки 1. Итак, мой вопрос: почему?

- (void) initCoordinateWithAddress:(NSString*)address;
{
self.address = address;

CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString: address completionHandler:^(NSArray *placemarks,NSError *error)
{
    CLPlacemark *place = [placemarks objectAtIndex:0];
    _coordinate = place.location.coordinate;
    _title = self.address;
    _subtitle = @"Test"; //Line 1: don't crash
     _subtitle = [NSString stringWithFormat: @"Test"]; //Line 2: crash
    //_subtitle = [[NSString stringWithFormat: @"[%.2f,%.2f]", self.coordinate.latitude, self.coordinate.longitude] copy];
    _isInit = YES;

    [self.customDelegate didCalculateCoordinate: place.location.coordinate forAnnotation: self];
}];

}

На самом деле я уже исправил свою проблему с помощью копирования метода, но я до сих пор не понимаю, в чем разница между строками 1 и 2, если кто-нибудь может помочь мне понять, в чем разница, я буду признателен.

Редактировать:

1- я не использую ARC

2- _subtitle происходит от @synthesize subtitle = _subtitle; И субтитры являются частью протокола MKAnnotation со свойством nonatomic, readonly и copy.

С уважением, Кирилл


person Cyril    schedule 29.05.2013    source источник
comment
Я думаю, что этот ответ подходит к вопросу: stackoverflow.com/a/4154419/883799   -  person geo    schedule 29.05.2013
comment
Вы можете проверить этот хороший ответ: stackoverflow.com/questions/8275131/   -  person Nishant Tyagi    schedule 29.05.2013
comment
В последний раз вы выполняете этот код в блоке, это может вызвать проблемы.   -  person Ben Coffman    schedule 29.05.2013
comment
Этот код использует ARC или ручной подсчет ссылок? Кроме того, что такое объявление _subtitle?   -  person JeremyP    schedule 29.05.2013
comment
Спасибо за ваши ответы. Итак, _subtitle происходит от @synthesize subtitle = _subtitle; А субтитры являются частью протокола MKAnnotation со свойствами неатомарными, только для чтения и копирования. И я не использую ARC.   -  person Cyril    schedule 29.05.2013


Ответы (5)


Если вы не используете ARC, ответ прост, и это то, что написал Ануп Вайда. Тем не менее, я думаю, что некоторые дополнительные пояснения необходимы.

Эта линия

_subtitle = @"Test";

Создает ссылку на строковый литерал. Если вы взглянете на количество сохранений в текущей реализации Foundation, вы обнаружите, что это очень большое число (NSIntegerMax я думаю). Если код для -release и -retain встречает это значение счетчика сохранения, он не уменьшает и не увеличивает его. Таким образом, строковые литералы имеют бесконечное время жизни.

Эта строка:

_subtitle = [NSString stringWithFormat: @"Test"];

создает строку, которой вы не владеете. Если вы не предпримете шаги, чтобы заявить о своем праве собственности, он может исчезнуть в любое время, скорее всего, когда пул автоматического выпуска будет опустошен. Ваши варианты - создать строку, которой вы владеете

_subtitle = [[NSString alloc] initWithFormat: @"Test"];

или сохранить его.

_subtitle = [NSString stringWithFormat: @"Test"];
[_subtitle retain]; // Can be combined with the previous line if you like.

или скопировать его

_subtitle = [[NSString stringWithFormat: @"Test"] copy];

Обратите внимание, что во всех случаях вам необходимо освободить предыдущее значение _subtitle, прежде чем перезаписывать его, иначе вы получите утечку, например.

[_subtitle release];
_subtitle = [[NSString alloc] initWithFormat: @"Test"];

Поэтому лучше иметь недвижимость. Тот факт, что свойство субтитров MKAnnotation доступно только для чтения, не означает, что вы не можете переопределить его собственным свойством для чтения/записи. например

@interface MyAnnotation : NSObject <MKAnnotation>

// other stuff

@property (readwrite, copy, nonatomic) NSString* subtitle; 

@end

Если вы затем синтезируете его, вы получите весь правильный код управления памятью, и вы можете просто сделать

[self setSubtitle: [NSString stringWithFormat: @"test"]];

или, если вы должны использовать запись через точку

self.subtitle = [NSString stringWithFormat: @"test"];
person JeremyP    schedule 30.05.2013

Я просто хотел бы знать разницу между строками 1 и 2 ниже:

_subtitle = @Тест; //Линия 1

_subtitle = [NSString stringWithFormat: @Test]; // Строка 2

Если вы спросите только вышеизложенное, они оба одинаковы.

При проверке вашего кода разница вполне заметна.

Вы создаете новый autoreleased subtitle, который освобождается после завершения блока.

person Anoop Vaidya    schedule 29.05.2013
comment
Не должно быть проблем с ARC - person JeremyP; 29.05.2013
comment
Хорошо, но я не использую ARC. Значит, строка 1 не создает авторелиз? Так почему же мы никогда не выпускаем объявление объекта так же, как в строке 1? Ваше здоровье, - person Cyril; 29.05.2013
comment
+1 Это правильный ответ, если вы не используете ARC. Я собирался написать длинный комментарий, чтобы объяснить это более подробно, но вместо этого напишу ответ. - person JeremyP; 30.05.2013
comment
@JeremyP: конечно, приятель. Будем знакомиться подробнее. - person Anoop Vaidya; 30.05.2013

Я не думаю, что ваше решение состоит не в том, чтобы понять, как работает инициализация строки, а в том, как блоки взаимодействуют с переменными.

Когда я думаю об этом, я думаю, что вы можете попробовать получить доступ к _subtitle по его свойству, а не по его ivar.

self.subtitle

Это должно увеличить счетчик сохранения и сохранить все в порядке.

person Ben Coffman    schedule 29.05.2013
comment
Не должно быть проблем с ARC - person JeremyP; 29.05.2013
comment
Почему только то, что ARC выполняет все управление памятью, не означает, что переменной не нужно увеличивать свой счетчик сохранения. Чего не происходит при доступе к ivar? - person Ben Coffman; 29.05.2013
comment
Но ARC должен увеличить количество сохранений для вас — при условии, что переменная равна __strong. - person JeremyP; 29.05.2013
comment
Точно, этого не происходит, когда вы обращаетесь к ivar напрямую. - person Ben Coffman; 29.05.2013
comment
да, это происходит с ARC. Я допускаю, что это может быть сломано, если вы сделаете это в блоке - person JeremyP; 29.05.2013
comment
Хм, приятно знать. :) Что касается того, что он находится в блоке, я думаю, что значение необходимо было присвоить, чтобы создать ссылку, как указано здесь. developer.apple.com/library/mac /#documentation/cocoa/Концептуальный/ - person Ben Coffman; 29.05.2013
comment
Спасибо за ответ, я не могу этого сделать, потому что свойство субтитров доступно только для чтения, поэтому у них нет установщика для обновления этого атрибута. И я не использую ARC! - person Cyril; 29.05.2013
comment
Весь смысл MKAnnotation в том, чтобы иметь возможность устанавливать свои свойства для каждого объекта. На вашем месте я бы изменил его и использовал настройки свойства. - person Ben Coffman; 29.05.2013

Если вы посмотрите документацию для initWithFormat: он связывает вас с Форматирование строковых объектов со множеством примеров.

Это в основном позволяет использовать строки формата (s) в стиле printf, например:

NSString *string1 = [[NSString alloc] initWithFormat:@"A string: %@, a float: %1.2f",
                                                     @"string", 31415.9265];

// string1 is "A string: string, a float: 31415.93"

Ключевым моментом является указание аргументов путем добавления , после строкового аргумента.

person Mike Weller    schedule 29.05.2013
comment
В @"Test" нет спецификаторов формата, поэтому аргументы не нужны. - person JeremyP; 29.05.2013

'[NSString stringWithFormat:]' позволяет добавить в строку переменную, например:

int myVar = 3;
NSString *myString = [NSString stringWithFormat:@"This number is %i", myVar];

Результирующая строка будет (если вы, например, использовали NSLog): «Это число равно 3»

Однако вы не можете сделать это так:

NSString *myString = @"This number is %i", myVar;

Что приведет вас к ошибке.

person nanothread    schedule 29.05.2013