Указатель отсутствует спецификатор типа 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 ответа:
необходимо указать
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.