Понимание initWithBytes для NSString

#objective-c

#objective-c

Вопрос:

Предполагая, что «someData» — это NSMutableData, содержащий несколько байтов данных.

Если я напишу следующее:

 NSString *someString = [NSString string];
[someString initWithBytes:[someData mutableBytes] length:[someData length] encoding:NSUTF8StringEncoding];
  

Вторая строка выдает ошибку «нераспознанный селектор, отправленный экземпляру»

Но если я напишу:

 NSString *someString=[[NSString alloc] initWithBytes:[someData mutableBytes] length:[someData length] encoding:NSUTF8StringEncoding];
  

тогда это работает. Есть ли причина, по которой первый способ не работает? Можно ли это сделать без «alloc» (предварительно создав someString?)

Спасибо.

Комментарии:

1. Вам следует прочитать основы » Языка программирования Objective-C «.

2. Ваш вопрос должен касаться alloc amp; init , а не этого NSString метода.

Ответ №1:

Причина в том, что объект, возвращаемый [NSString string] , не отвечает на селектор -initWithBytes:length:encoding: . Это потому, что NSString являются неизменяемыми — они не могут быть изменены после создания. Метод -string использует это преимущество и просто дает вам ссылку на постоянную строку (созданную во время компиляции), которая является пустой.

Не только это, но и NSString является кластером классов. Это означает, что когда вы запрашиваете NSString, вы можете фактически получить экземпляр одного из его подклассов. Я предполагаю, что вы получаете подкласс, который -initWithBytes:length:encoding: переопределен для создания исключения, потому что нет смысла отправлять метод init в постоянную строку, созданную во время компиляции.

Во втором случае вы создаете совершенно новую NSString во время выполнения, а затем отправляете ей сообщение init. Это совершенно нормально. Обратите внимание, что, поскольку это кластер классов, строка, возвращаемая методом init, может отличаться от той, которая была создана -alloc .

Комментарии:

1. Я думаю, что понимаю. В первом случае создается NSString во время компиляции. После создания он не может быть повторно инициализирован. Последний случай создает объект string во время выполнения и инициализирует его в той же строке. Однако замена второй строки в первом случае на [someString init] не приводит к ошибке. Возможно, это проблема кластера классов.

Ответ №2:

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

 @interface NSString (stringWithBytes)

  (NSString*)stringWithBytes:(const void *)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding;

@end

@implementation NSString (stringWithBytes)

  (NSString*)stringWithBytes:(const void *)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding {
    NSString * aString = [[NSString alloc] initWithBytes:bytes length:length encoding:encoding];
    return [aString autorelease];
}

@end
  

Комментарии:

1. Разве они не должны быть методами класса?

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

3. Я печатаю много ответов на своем телефоне . Это чудо, что у меня вообще есть репутация.