2013-03-06 4 views
0
NSMutableArray *array = [[NSMutableArray alloc] init]; 
NSString *string = @"string"; 
[array addObject:string]; 
NSDate *date = [[NSDate alloc] init]; 
[array addObject:date]; 

    for (*placeholder* stuff in array) 
     NSLog(@"one"); 

Если изменить заполнитель либо NSString * или NSDate *, я ожидал увидеть «один», потому что цикл должен просто игнорировать тип, не соответствующий. Однако результат «один».Зачем устанавливать типы в быстрых циклах перечисления Obj-c?

Не означает ли это, что у вас должно быть только placeholder быть какой бы ни была ситуация, поскольку это нисколько не имеет значения?

ответ

3

быстрое перечисление всегда выполняет итерации по всему объекту в коллекции. он не фильтрует.

Единственное, что происходит, это то, что у вас будут какие-то странные приведения.

если массив содержит объекты различных классов, вы можете определить класс для каждого объекта с isMemberOfClass:


, если вы могли бы сделать for (NSDate *obj in array), любой объект в массиве будет забросами к NSDate, независимо от того, то есть полный смысл или нет. и из-за характера объектива-c он даже будет работать, поскольку вы не отправляете сообщение, которое понятно только объектам NSDate или отправляет объект в качестве аргумента методу, который должен получать объект даты, в качестве cast не изменяет объект в любом случае. Бросок - это просто обещание, которое вы делаете компилятору, что вы знаете, что делаете. На самом деле вы также можете назвать это ложью.


Чтобы ответить на свое название вопроса: вам не нужно устанавливать класс внутри оператора цикла. достаточно общего типа объекта id. Но обычно у вас есть объекты одного вида в массиве - виды, числа, строка, даты, .... декларируя правильный класс, вы получаете некоторый комфорт, как лучшее автозаполнение.

+0

Можете ли вы рассказать о том, что вы подразумеваете под «странными кастами»? какие проблемы могут возникнуть? – hollow7

+0

, если вы сделаете 'for (NSDate * obj in array)', любой объект в массиве будет передан NSDate, независимо от того, является ли это полным смысла или нет. – vikingosegundo

+0

, и из-за характера объектива-c он даже будет работать, поскольку вы не отправляете сообщение, которое понятно только NSDate. – vikingosegundo

1

Да, с помощью id (или какого-либо другого общего класса-предка) правильный подход, а затем необходимо определить, какой тип класса уже было перечислено для того, чтобы справиться с этим по-разному:

for (id obj in array) 
{ 
    if ([obj isMemberOfClass:[NSString class]]) 
    { 
     NSString *str = (NSString *)obj; 
     NSLog("obj is a string: %@", str); 
    } 
    else if ([obj isMemberOfClass:[NSDate class]]) 
    { 
     NSDate *date = (NSDate *)obj; 
     NSLog("obj is a date: %@", date); 
    } 
} 
0

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

id lastObject = [array lastObject]; 

или

NSString *string = [array lastObject]; 

Что вы выбрали? Все зависит от вашего кода. Если вы уверены, что array содержит только строки, то, по моему мнению, лучше использовать второй вариант, потому что вы получаете дополнительную проверку типов, автозаполнение и соответствие методов от компилятора (то есть вы не получите предупреждений, если вы позвоните метод, который имеет разные сигнатуры для двух разных объектов). То же самое относится к быстрому перечислению: если ваша коллекция может содержать какой-либо объект, используйте id. Если вы знаете, что он содержит, используйте конкретный тип. (То же самое относится и к блоку тестов. В NSArray «s метод

- (NSUInteger)indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate 

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