ios – 如何在Objective-C中安全地将`_Nullable`强制转换为`_Non
使用-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. 如何安全地将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 force unwrap a null: " #nullableExpression); abort(); } }() 使用如下: NSString * _Nullable maybeFoo = @"foo"; if (maybeFoo) { NSString * _Nonnull foo = ForceUnwrap(NSString *,maybeFoo); ^(NSString * _Nonnull bar) { }(foo); } 如果分配给错误类型的变量,则会产生错误: NSString * _Nullable maybeFoo = @"foo"; if (maybeFoo) { NSNumber * _Nonnull foo = ForceUnwrap(NSString *,maybeFoo); ^(NSNumber * _Nonnull bar) { }(foo); } Tests.m:40:29: error: incompatible pointer types initializing 'NSNumber * _Nonnull' with an expression of type 'NSString * _Nonnull' [-Werror,-Wincompatible-pointer-types] NSNumber * _Nonnull foo = ForceUnwrap(NSString *,maybeFoo); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 error generated. 如果转换为错误的类型会产生错误: NSString * _Nullable maybeFoo = @"foo"; if (maybeFoo) { NSNumber * _Nonnull foo = ForceUnwrap(NSNumber *,maybeFoo); ^(NSNumber * _Nonnull bar) { }(foo); } Tests.m:40:35: error: incompatible pointer types initializing 'NSNumber * _Nullable' with an expression of type 'NSString * _Nullable' [-Werror,-Wincompatible-pointer-types] NSNumber * _Nonnull foo = ForceUnwrap(NSNumber *,maybeFoo); ^ ~~~~~~~~ Tests.m:27:16: note: expanded from macro 'ForceUnwrap' type _Nullable maybeValue___ = nullableExpression; ^ ~~~~~~~~~~~~~~~~~~ 1 error generated. 不幸的是,如果需要转换为具有多个参数的泛型类型,则必须求助于preprocessor hacks: NSDictionary<NSString *,NSString *> * _Nullable maybeFoo = [NSDictionary<NSString *,NSString *> new]; if (maybeFoo) { NSDictionary<NSString *,NSString *> * _Nonnull foo = #define COMMA,ForceUnwrap(NSDictionary<NSString * COMMMA NSString *>,maybeFoo); #undef COMMA ^(NSDictionary<NSString *,NSString *> * _Nonnull bar) { }(foo); } 我试过的东西不起作用 将maybeFoo直接分配给NSString * _Nonnull不起作用.它产生与以前相同的错误: NSString * _Nullable maybeFoo = @"foo"; if (maybeFoo) { NSString * _Nonnull foo = maybeFoo; ^(NSString * _Nonnull bar) { }(foo); } Tests.m:30:35: error: implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull' [-Werror,-Wnullable-to-nonnull-conversion] NSString * _Nonnull foo = maybeFoo; ^ 1 error generated. 并且转换为maybeFoo到NSString * _Nonnull是不安全的,因为如果maybeFoo的类型更改,编译器将不会中断: NSNumber * _Nullable maybeFoo = @"foo"; if (maybeFoo) { NSString * _Nonnull foo = (NSString * _Nonnull) maybeFoo; ^(NSString * _Nonnull bar) { }(foo); } // no errors! 我还尝试使用__typeof__,但是__typeof__带有可空性说明符,所以当你尝试强制转换为__typeof __(maybeFoo)_Nonnull时,你会得到一个可空性冲突: NSString * _Nullable maybeFoo = @"foo"; if (maybeFoo) { NSString * _Nonnull foo = (__typeof__(maybeFoo) _Nonnull) maybeFoo; ^(NSString * _Nonnull bar) { }(foo); } Tests.m:30:57: error: nullability specifier '_Nonnull' conflicts with existing specifier '_Nullable' NSString * _Nonnull foo = (__typeof__(maybeFoo) _Nonnull) maybeFoo; ^ Tests.m:30:35: error: implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull' [-Werror,-Wnullable-to-nonnull-conversion] NSString * _Nonnull foo = (__typeof__(maybeFoo) _Nonnull) maybeFoo; ^ 2 errors generated. 所有内容都使用深度静态分析器运行,并使用以下标志使用Xcode 8.2.1进行编译: -Wnon-modular-include-in-framework-module -Werror=non-modular-include-in-framework-module -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wno-missing-prototypes -Wunreachable-code -Wno-implicit-atomic-properties -Wno-arc-repeated-use-of-weak -Wduplicate-method-match -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wundeclared-selector -Wno-deprecated-implementations -Wno-sign-conversion -Wno-infinite-recursion -Weverything -Wno-auto-import -Wno-objc-missing-property-synthesis -Wno-cstring-format-directive -Wno-direct-ivar-access -Wno-double-promotion 解决方法
到目前为止我发现的最好的是泛型的技巧.
基本上,您定义了一个使用泛型的接口,并且有一个将泛型类型返回为非空的方法.然后在你的宏中你使用typeof但是在泛型类型上,这会给你正确的类型. 请注意,泛型类永远不会被实例化,它只是用于获取正确的类型. @interface RBBBox<__covariant Type> - (nonnull Type)asNonNull; @end #define RBBNotNil(V) ({ NSCAssert(V,@"Expected '%@' not to be nil.",@#V); RBBBox<__typeof(V)> *type; (__typeof(type.asNonNull))V; }) 不过,这不是我的想法.资料来源:https://gist.github.com/robb/d55b72d62d32deaee5fa (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |