使用Xcode 6.3,引入了新的注释,以便更好地表达Objective-C中API的意图(并确保更好的Swift支持).那些注释当然是nonnull,nullable和null_unspecified.
但是使用Xcode 7,会出现很多警告,例如:
指针缺少可为空类型说明符(_Nonnull,_Nullable或_Null_unspecified).
除此之外,Apple使用另一种类型的可为空性说明符,标记其C代码(源代码):
CFArrayRef __nonnull CFArrayCreate(?CFAllocatorRef __nullable allocator, const void * __nonnull * __nullable values, CFIndex numValues, const CFArrayCallBacks * __nullable callBacks);
总而言之,我们现在拥有这3种不同的可空性注释:
nonnull,nullable,null_unspecified_Nonnull,_Nullable,_Null_unspecified__nonnull,__nullable,__null_unspecified即使我知道为什么以及在哪里使用哪个注释,我也会对我应该使用哪种类型的注释,在哪里以及为什么感到困惑.这是我可以收集的:
nonnull,nullable,null_unspecified.nonnull,nullable,null_unspecified.__nonnull,__nullable,__null_unspecified._Nonnull,_Nullable,_Null_unspecified. …在Xcode 7 GM中,我开始收到此警告:
指针缺少可为空类型说明符(_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;
Run Code Online (Sandbox Code Playgroud)
为什么要显示此警告,我该如何解决?
我已经养成了一个很好的习惯,即为NSNotification名字之类的东西声明和使用常量字符串.我声明他们是这样的:
extern NSString * const ABCAwesomeThingHappenedNotification;
Run Code Online (Sandbox Code Playgroud)
随着引进的Xcode 6.3和1.2雨燕的,我要回去,使用新雨燕与互操作和审计Objective-C类nonnull,nullable和null_unspecified预选赛.
将限定符添加到也具有外部可见静态字符串的标头时,我收到以下警告:
警告:指针缺少可为空类型说明符(__nonnull或__nullable)
嗯.那令人困惑/有趣.有人可以解释这条消息背后的原因吗?ABCAwesomeThingHappenedNotification在Swift中使用时,它从不暗示它是可选的String或隐式解包的String.
从Xcode 6.3开始,Objective-C中的类型可以标记为nullable或者nonnull,这是Apple的博客文章.
问题是,当两者都没有指定时,编译器会将Objective-C代码导入隐式解包到Swift中,例如NSView!.因此,当一个对象实际上是 nil时,从Swift访问它时会崩溃.这并没有产生一个编译错误.
由于这非常容易失败,我希望编译器默认采用Objective-C中的所有内容nullable,除非另有指定nonnull,否则是审计区域宏NS_ASSUME_NONNULL_BEGIN / END.怎么能实现呢?
我最近一直在学习Swift.
我决定编写一个混合的Swift/Objective-C应用程序,它使用两种语言实现的相同算法完成计算密集型任务.
该程序计算大量素数.
我定义了一个协议,Swift和Objective-C版本的计算对象都应该符合.
对象都是单例,所以我在Objective-C中创建了一个典型的单例访问方法:
+ (NSObject <CalcPrimesProtocol> *) sharedInstance;
Run Code Online (Sandbox Code Playgroud)
整个协议看起来像这样:
#import <Foundation/Foundation.h>
@class ComputeRecord;
typedef void (^updateDisplayBlock)(void);
typedef void (^calcPrimesCompletionBlock)(void);
@protocol CalcPrimesProtocol <NSObject>
- (void) calcPrimesWithComputeRecord: (ComputeRecord *) aComputeRecord
withUpdateDisplayBlock: (updateDisplayBlock) theUpdateDisplayBlock
andCompletionBlock: (calcPrimesCompletionBlock) theCalcPrimesCompletionBlock;
@optional //Without this @optional line, the build fails.
+ (NSObject <CalcPrimesProtocol> *) sharedInstance;
@end
Run Code Online (Sandbox Code Playgroud)
该类的Objective-C版本完全按照上面的定义实现方法,不用担心.
swift版本有一个方法:
class func sharedInstance() -> CalcPrimesProtocol
Run Code Online (Sandbox Code Playgroud)
但是,如果我使该方法成为协议的必需方法,我得到编译器错误"类型"CalcPrimesSwift不符合协议'CalcPrimesProtocol'.
但是,如果我在协议中将单例类方法sharedInstance标记为可选,那么它可以工作,我可以在我的Swift类或Objective-C类上调用该方法.
我是否错过了Swift类方法定义中的一些细微之处?考虑到我可以在我的Swift类或Objective-C类上调用sharedInstance()类方法,这似乎不太可能.
您可以从Github下载该项目,如果您愿意,可以查看它.它叫做SwiftPerformanceBenchmark.(链接)
interop objective-c objective-c-protocol swift objective-c-nullability
我在Objective-C中编写了一组工具,Swift将在某些时候使用这些工具,因此我使用了泛型和可空性.在这种情况下我该怎么办?
- (NSArray<MyObj *> * __nullable)foo:(NSError **)error;
Run Code Online (Sandbox Code Playgroud)
目前我收到警告:Pointer is missing a nullability type specifier...两个指针!我几乎可以肯定我不应该这样做:
- (NSArray<MyObj *> * __nullable)foo:(NSError * __autoreleasing __nullable * __nullable)error;
Run Code Online (Sandbox Code Playgroud)
我呢?
这是一个如何优雅地规避课堂上的可空性的init问题NSObject.
所以这是一个经典的objective-c实现:
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
static id sharedInstance;
dispatch_once(&onceToken, ^
{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Run Code Online (Sandbox Code Playgroud)
但是现在我想声明它nonnull,如果可能的话:
+ (nonnull instancetype)sharedInstance;
Run Code Online (Sandbox Code Playgroud)
不幸的是,init返回一个nullable instancetype值.我应该NSAssert在打电话后添加一个什么东西init?
我注意到有些人甚至将价值观记录nonnull在现实中nullable.那有意义吗?
我应该大胆地简单地添加到NS_ASSUME_NONNULL_BEGIN任何地方,而不是真正确保价值观nonnull吗?
nullable objective-c init non-nullable objective-c-nullability
使用CLANG_ANALYZER_NONNULL(ie -Xclang nullability),我得到“ 从预期返回非空值的函数返回Null ”:

使用Xcode 7.3和iOS 9.3文档,我检查了一下initWithFrame:,它可以返回nil:

但是UIView.h用封装了所有内容NS_ASSUME_NONNULL_BEGIN,因此我们可以解释以下内容:

如:
- (nonnull instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
Run Code Online (Sandbox Code Playgroud)
因此文档说明了nullable,而标头文件说明了nonnull。信任哪一个?
我应该写:
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) {
// workaround for clang analyzer
return (void * _Nonnull)nil;
}
// Initialization code
return self;
}
Run Code Online (Sandbox Code Playgroud)
要么:
- (nonnull instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
// Initialization code
return self;
}
Run Code Online (Sandbox Code Playgroud)
Xcode文档已更新,现在为:

因此,不再有冲突。
objective-c uiview ios initwithframe objective-c-nullability
+ (UIColor*) getColorWithHexa(NSString*)hexString;
Run Code Online (Sandbox Code Playgroud)
这是我班上的方法定义.这引起了警告.什么是类似警告的原因以及如何解决这些问题?
我正在返回一个UIColor对象,而该问题与块有关,在注释中给出.
所以,它很有帮助.
在编译时-Wnullable-to-nonnull-conversion,我们会使用以下代码获得正确的警告:
NSString * _Nullable maybeFoo = @"foo";
^(NSString * _Nonnull bar) {
}(maybeFoo);
Tests.m:32:7: error: implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull' [-Werror,-Wnullable-to-nonnull-conversion]
}(maybeFoo);
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
我如何安全地foo从一个演员阵容NSString * _Nullable到一个NSString * _Nonnull?
到目前为止我有最好的解决方案
我想出的最好的就是这个宏:
#define ForceUnwrap(type, nullableExpression) ^type _Nonnull () { \
type _Nullable maybeValue___ = nullableExpression; \
if (maybeValue___) { \
return (type _Nonnull) maybeValue___; \
} else { \
NSLog(@"Attempted to …Run Code Online (Sandbox Code Playgroud) objective-c ×9
ios ×4
swift ×4
nullable ×3
interop ×2
init ×1
non-nullable ×1
uiview ×1
xcode ×1