#objective-c #foundation #variadic-functions
#objective-c #foundation #переменные функции
Вопрос:
Я слежу за программированием Стивена Кочана на Objective-C, 6-е издание, и мне нужна помощь с этим конкретным методом. В принципе, у меня есть класс, AddressBook
, который имеет две переменные экземпляра: NSMutableArray
вызываемый book
и NSString
вызываемый bookName
. Вполне понятно.
book
содержит AddressCard
s, и я пытался реализовать метод, который принимает несколько переменных типа id
и добавляет их все в массив book
. Вот оно:
-(void) addCards:(id)firstCard, ... NS_REQUIRES_NIL_TERMINATION
{
va_list argumentList;
va_start(argumentList, firstCard);
id theArgument = firstCard;
while ((theArgument = va_arg(argumentList, id)))
{
[self addCard:theArgument];
}
va_end(argumentList);
}
addCard
Метод представляет собой настраиваемую реализацию NSMutableArray
addObject
метода. Проблема в том, что первый аргумент, который я предоставляю addCards
, не добавляется book
. Вот main.m
и сопутствующий вывод:
int main(int argc, const char * argv[])
{
@autoreleasepool
{
AddressCard *card1 = [[AddressCard alloc] initWithName:@"Joseph Brown" andEmail:@"jbrown@yahoo.com"];
AddressCard *card2 = [[AddressCard alloc] initWithName:@"Thomas Walter" andEmail:@"t.walter@gmail.com"];
AddressCard *card3 = [[AddressCard alloc] initWithName:@"Jonathan Green" andEmail:@"jon_green@gmail.com"];
AddressCard *card4 = [[AddressCard alloc] initWithName:@"Elizabeth White" andEmail:@"elizwhite@live.com"];
AddressBook *myBook = [[AddressBook alloc] initWithName:@"My Address Book"];
[myBook addCards:card1, card2, card3, card4, nil];
NSLog(@"Lookup: Joseph Brown");
if ([myBook lookup:@"joseph Brown"] == nil)
{
NSLog(@"Not Found!");
}
else
{
[[myBook lookup:@"Joseph Brown"] print];
}
[myBook list];
}
return 0;
}
Вывод:
2014-06-25 11:43:25.997 AddressBook[19454:303] Lookup: Joseph Brown
2014-06-25 11:43:25.999 AddressBook[19454:303] Not Found!
2014-06-25 11:43:25.999 AddressBook[19454:303] ======== Contents of My Address Book ========
2014-06-25 11:43:26.000 AddressBook[19454:303] Thomas Walter t.walter@gmail.com
2014-06-25 11:43:26.000 AddressBook[19454:303] Jonathan Green jon_green@gmail.com
2014-06-25 11:43:26.000 AddressBook[19454:303] Elizabeth White elizwhite@live.com
2014-06-25 11:43:26.001 AddressBook[19454:303] =============================================
Program ended with exit code: 0
lookup
делает именно это: ищет AddressCard
указанное в аргументе для него; print
печатает AddressCard
в удобном формате; list
также выполняет его тезку: перечисляет содержимое book
. Теперь, как видно из выходных данных, Joseph Brown
, хотя и добавляется в AddressBook
as card1
, на самом деле не добавляется, что дважды подтверждается выводом. Что не так?
Комментарии:
1. Рассмотрите возможность использования массива вместо этого. Мне было очень сложно отлаживать код с переменными аргументами. Требуется три символа, чтобы обернуть ваш список карточек в массив.
2. Достаточно справедливо; Я сначала подумал об этом. Но разве элементы уже не входят в массив? Я решил не делать этого, потому что это было неэффективно; зачем инициализировать массив, чтобы поместить его элементы в другой массив? Если бы мне действительно нужно было, я мог бы использовать arrayWithArray: или arrayWithObjects: для этого, я полагаю. Но почему именно, помимо простоты отладки?
3. Более чистый код, НАМНОГО более чистый код. Кроме того, вам нужно всего три символа, чтобы обернуть ваши карты в массив, и вам не нужно беспокоиться о завершении nil.
[myBook addCards:@[card1, card2, card3, card4]];
Ответ №1:
Альтернативное решение с использованием NSArray
…
AddressCard *card1 = [[AddressCard alloc] initWithName:@"Joseph Brown" andEmail:@"jbrown@yahoo.com"];
AddressCard *card2 = [[AddressCard alloc] initWithName:@"Thomas Walter" andEmail:@"t.walter@gmail.com"];
AddressCard *card3 = [[AddressCard alloc] initWithName:@"Jonathan Green" andEmail:@"jon_green@gmail.com"];
AddressCard *card4 = [[AddressCard alloc] initWithName:@"Elizabeth White" andEmail:@"elizwhite@live.com"];
AddressBook *myBook = [[AddressBook alloc] initWithName:@"My Address Book"];
[myBook addCards:@[card1, card2, card3, card4]];
-(void)addCards:(NSArray *)cards {
for (AddressCard *card in cards) {
[self addCard:card];
}
}
Комментарии:
1. Спасибо за предложение. Я совершенно забыл о быстром перечислении и литералах Obj-C. Для еще большего сокращения кода, я полагаю, можно использовать arrayWithArray: ?
2. Я имел в виду, что вместо перечисления через массив карточек вы могли бы просто сделать
[self.book arrayWithArray:cards];
.3. Это не так, как работает arrayWithArray… Это статический метод, который возвращает копию массива. Вы не поделились структурой класса AddressBook, поэтому я не могу это прокомментировать.
4. Возможно, вы думали
arrayByAddingObjectsFromArray:
.
Ответ №2:
В вашем коде
id theArgument = firstCard;
while ((theArgument = va_arg(argumentList, id)))
вы ничего не делали с. firstCard
второй аргумент переопределяет его
-(void) addCards:(id)firstCard, ... NS_REQUIRES_NIL_TERMINATION
{
va_list argumentList;
va_start(argumentList, firstCard);
id theArgument = firstCard;
while (theArgument)
{
[self addCard:theArgument];
theArgument = va_arg(argumentList, id);
}
va_end(argumentList);
}
Комментарии:
1. Ах, да, я должен был это понять. Большое спасибо.