【问题标题】:Checking if [NSObject : AnyObject]! is NSNull in Swift检查是否 [NSObject : AnyObject]!在 Swift 中是 NSNull
【发布时间】:2016-05-10 09:51:56
【问题描述】:

我的项目同时使用 Swift 和 Objective C。我有一个用 Objective C 编写的单例,它是 NSDictionary 类型的属性。

@property(nonatomic, strong) NSDictionary *currentDictionary;

这是一个在我的整个项目中使用的旧类。我正在尝试在这样的 Swift 类中使用这个类

if let dict = DataManager.sharedManager().currentDictionary
{
   // 
}

我面临的问题是 currentDictionary 正在使用来自服务器的数据进行设置。有时这可能是

在 Objective C 类中,我可以通过以下检查来处理这种情况

if ([currentDictionary isKindOfClass: [NSNull class]])
{
   // Do nothing
}

但我不确定如何在 Swift 中实现类似的检查。我尝试了以下

if let data = DataManager.sharedManager().currentDictionary as? NSNull
{
    return 
}

但它不起作用,而且我收到编译器警告:

“从“[NSObject : AnyObject]!”转换为不相关类型“NSNull”总是失败”

这与检查字典中的 Null 值不同,因为它们将是“AnyObject”,我可以尝试将它们转换为我想要检查的类型。

有人可以提供有关如何正确处理这种情况的任何指示

【问题讨论】:

  • NSDictionary 应该永远NSNull 类型。它的内容可能是,但不是字典本身。
  • 这篇文章可能对你有用stackoverflow.com/questions/24026609/…
  • @luk2302 .. 是的,不应该。我已经与服务器端进行了相同的沟通。但我也想在客户端添加安全检查。
  • 正如@luk2302 所说:如果有问题,你应该有nil,但是NEVER EVER NSNull.
  • 没有什么可以交流的。它不得NSNull。指定类型是有原因的!您的 only 选项是解析您从服务器收到的响应并确定它是否是实际内容 -> 将其放入字典 如果它是 @ 987654329@、nil 或任何您创建空字典或将字典设置为 nil 的内容,您不要将字典本身设置为 NSNull。与您不将其设置为字面意义上的 @"no value present"@(-2) 的方式相同。

标签: objective-c swift type-safety


【解决方案1】:

首先,如果变量可以包含NSDictionary 之外的其他内容,请不要将其类型设置为NSDictionary。 Swift 是类型安全的,它会信任声明的类型。

最简单的解决方法是在 Objective-C 中将其设为 id

然后在 Swift 中你可以简单地:

guard let data = DataManager.sharedManager().currentDictionary as? NSDictionary else {
    return 
}

如果您无法更改原始代码,只需使用类别创建具有正确类型的 Swift 访问器,例如

@interface DataManager (Swift)

// solution 1, will be converted to AnyObject in Swift
- (id)currentDictionaryForSwift1;

// solution 2, let's handle NSNull internally, don't propagate it to Swift
- (NSDictionary *)currentDictionaryForSwift2;

@end

@implementation DataManager

- (id)currentDictionaryForSwift1 {
   return self.currentDictionary;
}  

- (NSDictionary *)currentDictionaryForSwift2 {
   if (self.currentDictionary == [NSNull null]) { 
      return nil;
   }

   return self.currentDictionary;
}    

@end

我建议您在内部处理 NSNull。应该不需要其他代码单独处理nilNSNull

您实际上可以在 getter 中解决它:

- (NSDictionary *)currentDictionary {
   if (_currentDictionary == [NSNull null]) {
      return nil;
   }

   return _currentDictionary;
}

或在设置器中

- (void)setCurrentDictionary:(NSDictionary *)currentDictionary {
    if (currentDictionary == [NSNull null]) {
       _currentDictionary = nil;
    } else {
       _currentDictionary = currentDictionary;
    }
}

如您所见,有多种解决方案,但最好的解决方案甚至可以改进您的 Obj-C 代码。 NSNullnil 之间的差异应该在本地处理,而不是传播。

【讨论】:

    【解决方案2】:

    如果您想验证currentDictionary 是否为nil,您可以使用:

    guard let currentDictionary = DataManager.sharedManager().currentDictionary else {
        return
    }
    

    如果您不想提前返回,请将 guard-else 语句替换为 if-else

    如果要验证currentDictionary 的内容是否为NSNull

    if let value = DataManager.sharedManager().currentDictionary["key"] {
        // do something with value
    }
    

    【讨论】:

    • 我确实尝试了保护语句,但它也无济于事。我认为它检查 nil ,它失败了,因为实际上有一个 NSNull 对象
    • 如果你使用guard DataManager.sharedManager().currentDictionary is NSNull else { return }会怎样?
    • 生成同样的警告
    猜你喜欢
    • 2016-11-19
    • 1970-01-01
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 2017-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多