#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. Я печатаю много ответов на своем телефоне . Это чудо, что у меня вообще есть репутация.