Указатель отсутствует спецификатор типа nullability


в Xcode 7 GM я начал получать это предупреждение:

указатель отсутствует спецификатор типа nullability (_Nonnull, _Nullable или _Null_unspecified)

в следующем объявлении функции (расширение NSUserDefaults)

- (void)setObject:(nullable id)value
           forKey:(NSString *)defaultName
    objectChanged:(void(^)(NSUserDefaults *userDefaults, id value))changeHandler
    objectRamains:(void(^)(NSUserDefaults *userDefaults, id value))remainHandler;

почему это предупреждение отображается и как я должен это исправить?

4   53  

4 ответа:

необходимо указать nullable также для обработчиков / блоков

- (void)setObject:(nullable id)value
           forKey:(nonnull NSString *)defaultName
    objectChanged:(nullable void(^)(NSUserDefaults *userDefaults, id value))changeHandler
    objectRamains:(nullable void(^)(NSUserDefaults *userDefaults, id value))remainHandler;

почему? Это из-за Свифта. Swift позволяет дополнительные параметры (?), который Objective-C не делает. Это делается как мост между ними обоими, чтобы компилятор Swift знал, что эти параметры являются необязательными. "Nonnull" сообщит компилятору Swift, что аргумент является обязательным. A nullable, что это необязательно

для получения дополнительной информации читать: https://developer.apple.com/swift/blog/?id=25

вы можете использовать следующие макросы вокруг блоков объявлений (функций и переменных) в заголовках objective c:

NS_ASSUME_NONNULL_BEGIN 

NS_ASSUME_NONNULL_END

затем вам нужно добавить аннотации с нулевым значением для ссылок, которые могут быть равны нулю в этом блоке. Это относится как к параметрам функции, так и к объявлениям переменных.

в:

@interface SMLBaseUserDetailsVC : UIViewController < UICollectionViewDelegate>
NS_ASSUME_NONNULL_BEGIN

@property (nonatomic, readonly) IBOutlet UIScrollView *detailsScrollView;
@property (nonatomic, readonly) IBOutlet UICollectionView *photoCV;
@property (nonatomic, weak, readonly) SMLUser *user;
- (IBAction)flagUser:(id)sender;
- (IBAction)closeAction:(nullable id)sender;
- (void) prefetchPhotos;

NS_ASSUME_NONNULL_END

@end

правка* почему??? потому что для того, чтобы класс objective-c был совместим с swift, вам нужно объявить nullability, чтобы компилятор знает, чтобы рассматривать свойства как swift optionals или нет. Свойства nullable objective c известны как optionals в swift и использование этих макросов в сочетании с деклараторами nullable для свойств позволяет компилятору рассматривать их как optionals (Optionals - это монады-объект, который обертывает либо объект, либо nil).

правильное, рабочее объявление метода, принятое компилятором:

- (void)setObject:(nullable id)value
           forKey:(nonnull NSString *)defaultName
    objectChanged:(nullable void(^)(NSUserDefaults *_Nonnull userDefaults, id _Nullable value))changeHandler
    objectRamains:(nullable void(^)(NSUserDefaults *_Nonnull userDefaults, id _Nullable value))remainHandler;

я публикую этот ответ, чтобы сказать, почему следует добавить _Nonnull или nullable.

согласно этому блогу:https://developer.apple.com/swift/blog/?id=25

одна из замечательных особенностей Swift заключается в том, что он прозрачно взаимодействует с кодом Objective-C, как существующими фреймворками, написанными на Objective-C, так и кодом в вашем приложении. Однако в Swift существует сильное различие между необязательными и необязательными ссылками, например NSView и NSView?, в то время как Objective-C представляет оба этих типа как NSView *. Потому что компилятор Swift не может быть уверен, является ли конкретный NSView * является необязательным или нет, тип вводится в Swift как неявно развернутый необязательный,NSView!.

все для Swift.