Objective-C дженерики, не работающие на методы? (Xcode 7 Beta (сборка: 7A120f))

Итак, очевидно, после WWDC я играю с новыми материалами, представленными на прошлой неделе. Как вы знаете, Apple ввела дженерики в мир Objective-C

Примечание. Этот ответ является последовательным ответом на этот вопрос: Существуют ли строго типизированные коллекции в Objective-C?

Я пробовал этот код в методе, отлично работает

NSMutableArray<NSString*> *array = [[NSMutableArray alloc] init];

[array addObject:@""];
[array addObject:@(54)];Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString * __nonnull'
// Great, generics works as expected.

Однако у меня также есть метод, который я хочу преобразовать в generics

В заголовочном файле:

- (NSArray <NSString*> *)objectsToSearch;

Реализация:

- (NSArray <NSString*> *)objectsToSearch
{
    NSString *first = @"1";

    NSString *second = @"2";

    NSString *third = @"3";

    NSNumber *test = @(55);

    return @[first, second, third, test]; // No-error!!!
}

Я делаю что-то не так, или Кланг не поддерживает дженерики + литералы или что-то еще мне не хватает?

Ответ 1

Я только что диагностировал это еще немного, и я не думаю, что это ошибка. Следующий код показывает множество вариантов и почему каждый будет или не будет компилироваться. Примечание. Это основано на моих догадках о том, как все работает. Это может отличаться от того, как Apple объяснит это.

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
-(void) testGenericArrays {

    NSString *aString = @"abc";
    NSNumber *aNumber = @(55);

    NSArray<NSString *> *arr1  = @[aString, aNumber];
    // Compiles because the RHS is an un-typed array at compilation time.

    NSArray<NSString *> *arr2  = @[aString, @(20)];
    // Compiles because the RHS is an un-typed array at compilation time.

    NSArray<NSString *> *arr3 = [NSArray<NSString *> arrayWithObjects:aString, aNumber, @(20), nil];
    // Compiles because the type erasure for arrayWithObjects only types the first argument which is a NSString.
    // The rest of the arguments are a vaList which is not checked during header processing.

    NSArray<NSString *> *arr4 = [NSArray<NSString *> arrayWithObjects:@(20), nil]; // <- Error!
    NSArray<NSString *> *arr5 = [NSArray<NSString *> arrayWithObjects:aNumber, nil]; // <- Error!
    // Neither of these two compile because the first argument is now a NSNumber and is checked.

    NSArray<NSString *> *arr6 = [NSArray<NSString *> arrayWithObject:aNumber]; // <- Error!
    // Doesn't compile because the argument is checked during header processing.

    NSArray<NSString *> *arr7 = [NSArray arrayWithObject:aNumber];
    // Compiles because the RHS is an un-typed array at compilation time.

    NSMutableArray<NSString *> *arr8 = [[NSMutableArray alloc] init];
    [arr8 addObject:aNumber]; // <- Error!
    // Doesn't compile because the LHS is a typed array and we are adding to it.
}
#pragma clang diagnostic pop

Надеюсь, это прояснит ситуацию для людей. Не стесняйтесь вырезать и вставлять в unit test и попробовать сами.

Ответ 2

Не предполагайте, что Apple добавляет generics в Obj-C, потому что они хотят улучшить Obj-C. Настоящая причина в том, что все фреймворки iOS/OS X, написанные в Obj-C, очень трудны в использовании в Swift - вам нужно отбросить все из AnyObject.

Добавление дженериков в Obj-C позволяет Apple правильно маркировать методы, например.

@property(nonatomic, readonly, copy) NSArray <__kindof UIView *> *subviews

Важно то, что теперь Swift может работать с фреймворками намного лучше. Реализация предупреждений/ошибок для неправильного использования дженериков в Obj-C не так важна, поэтому мы можем ожидать много ошибок там.

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

Ответ 3

Я бы согласился, что это ошибка. Я протестировал более простую версию вашего дела, и она все еще терпит неудачу.

NSString *first = @"1";
NSString *second = @"2";
NSString *third = @"3";
NSNumber *test = @(55);

NSArray <NSString*>* arr  = @[first, second, third, test, @(20)];

Это не похоже на синтаксис литерала массива. Эта строка по-прежнему не вызывает ошибок.

NSArray <NSString*>* anotherArray = [NSArray arrayWithObjects:first, second, third, test, @(20), nil];

Ответ 4

Я только что наткнулся на этот пост, и я не получаю одинаковых результатов. Я разрезал и вставил код в XCode для подтверждения, и все приведенные выше примеры порождают ошибки (у меня есть предупреждения, установленные для ошибок). Поэтому я не вижу ошибку. Либо это, либо есть где-то компилятор, который отличается от нас.