【问题标题】:Objective-C isEmpty helper suddenly stopping buildObjective-C isEmpty 助手突然停止构建
【发布时间】:2014-01-08 13:31:56
【问题描述】:

我在一个项目中拥有这个漂亮且方便的辅助内联函数(最初源于 herehere):

static inline BOOL isEmpty(id thing) {
    return !thing
    || [thing isKindOfClass:[NSNull class]]
    || ([thing respondsToSelector:@selector(length)] && [((id)thing) length] == 0)
    || ([thing respondsToSelector:@selector(count)] && [((id)thing) count] == 0);
}

static inline BOOL isNotEmpty(id thing) {
    return !isEmpty(thing);
}

一切正常。

它对于检查 NSString、NSData、NSArray、NSDictionary、NSSet 等很有用...我现在的问题是我将它带入另一个项目(我将使用的静态框架/库)并拥有以下问题阻止了我的项目构建:

我使用的是相同(最新)版本的 xCode,所以不确定有什么区别会在一侧而不是另一侧阻止这种情况......两个项目中的项目设置显然不同(如提到了,一个是框架,一个是常规项目)但是那样做吗?

提前致谢!


后解决方案编辑以供将来访问:

按住命令并单击方法或属性以获取编译器看到的所有实例的下拉列表...您可能有冲突的返回类型。

【问题讨论】:

  • 为什么叫它宏?它是一个内联函数?
  • 为了正确而改了。我意识到,但在精神上我或多或少将两者等同起来...... :-)
  • 宏可能有很多奇怪的副作用,如果不放在一个假循环中来确定它们的范围等,就会中断
  • 好奇你为什么要使用isEmpty?似乎nil 可以是您的空值。您不知道对象的预期类型吗?否则,如果您想检查一个数组(例如)是nil 还是一个空数组,只需使用array.count == 0。这将处理一个nil 数组和一个空数组,等等。
  • 持续检查 NSNull 对我来说也是一个问题。我做了很多 JSON 解析以及与服务器端点的大量通信......在从 json 中提取之后以及在使用它们之前检查字段或检查变量时,这个函数会发挥很大作用。就个人而言,拥有这样的东西是一个很好的抽象层次。

标签: ios objective-c xcode


【解决方案1】:

听起来问题在于框架/库中的某些类声明了一个-count 方法,该方法返回的内容不同于-[NSArray count](等等)。

即使您向未知 (id) 类型的对象发送消息,编译器也需要知道有关将被调用的方法的一些信息,包括返回类型。简而言之,这是因为消息发送路径根据将要调用的方法的返回类型而有所不同。在像您的代码这样的情况下,编译器将查找项目中声明的名称与您发送的消息匹配的任何方法,并假定该方法将被调用以计算返回类型等。在此在这种情况下,它会找到两个具有相同名称但返回类型不同的不同方法,因此不知道发送 count 消息所需的确切语义。

快速而肮脏的解决方案是将isEmpty() 函数中的演员表更改为[(NSArray *)thing count]。只要您从不使用具有不同 -count 方法的任何类的实例调用 isEmpty(),这应该可以正常工作。

【讨论】:

  • 是的,我意识到这一点,但这件事的美妙之处在于,在这种情况下,它与您使用的数据类型无关......我可以为每个条件设置多个条件,但宁愿不...更大的问题是为什么它可以在我在应用商店中使用的应用程序中工作,但在我正在构建的这个框架中却不行?
  • 对,但转换为NSArray 并不意味着thing 必须成为 NSArray。它只是告诉编译器将其视为一个,并假设将被调用的-count 方法将匹配NSArray 的计数方法。这个isEmpty() 函数依赖于这样一个事实:对于普通集合类(NSArrayNSSetNSDictionary 等),-count 的声明方式相同(-(NSUInteger)count;)。
  • 所以您是说我可以将其转换为 NSArray 而不必担心传入 NSDictionary 或 NSSet?有趣的
  • 是的。请记住,调用isEmpty(someFrameworkObject) 不会安全,其中someFrameworkObject 是框架中具有不同类型-count 方法的任何类的实例。跨度>
  • 当然。所以我刚刚发现了相互冲突的“计数”......这是我的一类的(int)属性。我会将您标记为您的帮助的正确答案,我很感激。为了将来访问的可见性,请在您的回答中记下以下内容:按住命令并单击有错误的属性名称以获取编译器看到的所有定义的下拉列表,这反过来又很严重有助于追踪冲突。
【解决方案2】:

update:将方法的含义改为not为空,也可以处理nil值。

不是一个完整的答案,但您可以使用类别来做到这一点:

@interface NSObject (IsEmpty)
-(BOOL)isNotEmpty ;
@end

@implementation NSObject (IsEmpty)
-(BOOL)isNotEmpty { return NO ; /* I guess? */ }
@end

@implementation NSArray (IsEmpty)
-(BOOL)isNotEmpty { return self.count > 0 ; }
@end

@implementation NSDictionary (IsEmpty)
-(BOOL)isNotEmpty { return self.count > 0 ; }
@end

@implementation NSSet (IsEmpty)
-(BOOL)isNotEmpty { return self.count > 0 ; }
@end

@implementation NSNull (IsEmpty)
-(BOOL)isNotEmpty { return NO ; }
@end

现在你可以这样做了:

id objectOrNil = ... ;
BOOL isEmpty = ![ objectOrNil isNotEmpty ] ;

【讨论】:

    【解决方案3】:

    我想正确的方法是将[thing count] 的结果显式转换为整数:

    static inline BOOL isEmpty(id thing) {
        return !thing
        || [thing isKindOfClass:[NSNull class]]
        || ([thing respondsToSelector:@selector(length)] && [((id)thing) length] == 0)
        || ([thing respondsToSelector:@selector(count)] && (NSUInteger)[((id)thing) count] == 0);
    }
    

    这将告诉编译器您希望看到无符号整数作为此方法调用的结果。

    【讨论】:

      【解决方案4】:
      static inline BOOL isEmpty(id thing) {
      return !thing
      || [thing isKindOfClass:[NSNull class]]
      || ([thing respondsToSelector:@selector(length)]
          && [(NSData *) thing length] == 0)
      || ([thing respondsToSelector:@selector(count)]
          && [(NSArray *) thing count] == 0);
      

      }

      它不应该与 [NSArray count] 方法混淆。希望这会有所帮助。

      【讨论】:

      • 是的,这里的问题是这仅适用于 NSData 和 NSArray 而不是我传递给它的所有其他类
      • 不仅是 NSArray,还可以用于其他数据结构,就像上面提到的 @Andrew Madsen。
      猜你喜欢
      • 1970-01-01
      • 2022-01-10
      • 1970-01-01
      • 2010-10-31
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多