加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-14 17:52:02 所属栏目:百科 来源:网络整理
导读:使用-Wnullable-to-nonnull-conversion进行编译时,我们会使用以下代码获得正确的警告: NSString * _Nullable maybeFoo = @"foo";^(NSString * _Nonnull bar) { }(maybeFoo);Tests.m:32:7: error: implicit conversion from nullable pointer 'NSString * _N
使用-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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读