ios – 如何在Objective-C中安全地将`_Nullable`强制转换为`_Nonnull`?

ios – 如何在Objective-C中安全地将`_Nullable`强制转换为`_Nonnull`?,第1张

概述使用-Wnullable-to-nonnull-conversion进行编译时,我们会使用以下代码获得正确的警告: NSString * _Nullable maybeFoo = @"foo";^(NSString * _Nonnull bar) { }(maybeFoo);Tests.m:32:7: error: implicit conversion from nullable po 使用-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

总结

以上是内存溢出为你收集整理的ios – 如何在Objective-C中安全地将`_Nullable`强制转换为`_Nonnull`?全部内容,希望文章能够帮你解决ios – 如何在Objective-C中安全地将`_Nullable`强制转换为`_Nonnull`?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/web/1020327.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存