【问题标题】:Cocoa -- toggling a BOOL without repeating its nameCocoa - 切换 BOOL 而不重复其名称
【发布时间】:2011-03-19 19:15:41
【问题描述】:

如果 BOOL 有一个不错的短名称,那么编写起来很容易:

myBOOL = !myBOOL;

但是如果 BOOL 有一个长名称怎么办?

objectWithLongishName.memberWithLongishName.submember.myBOOL = !(objectWithLongishName.memberWithLongishName.submember.myBOOL);  

。 . .看起来不那么漂亮。

我想知道是否有一种简单的方法来切换 BOOL 而无需输入其名称两次?

【问题讨论】:

  • 只是好奇,你能把 bool 乘以 Objective-C 中的数字吗?你能做类似objectWithLongishName.memberWithLongishName.submember.myBOOL*=-1; 的事情吗?这似乎是一个非常非常不好的方法,但我现在只是想知道它是否会起作用......
  • @frust:除了其他问题,这在算术上是如何工作的? 0 * -1 = 0.
  • @Georg Fritzsche:哈哈哈!好的,好点。我以为我在 some 哪里见过这个技巧,但我不记得在哪里(尽管我知道它不是 Objective-C)。
  • 你可以想象myBool ^= 1...但我不会。
  • @William:你真的应该指定一个平台。 BOOL 数据类型和 YES/NO 常量不是 Objective C 的一部分,它们是在 Cocoa 头文件中定义的。 Objective C 和 C 一样,没有布尔数据类型。

标签: objective-c cocoa boolean


【解决方案1】:

不,(Objective-)C 中没有明显的方法来执行您所描述的操作(不使用预处理器宏),但请参阅 Seva 的答案以获得可能的(尽管可能很脆弱)解决方案。更重要的是,objectWithLongishName.memberWithLongishName.submember.myBOOL 之类的内容表示 Law of Demeter 违规;您应该将submember 直接提供给需要访问submember.myBOOL 的任何代码单元。

【讨论】:

  • 为什么 aBool ^= YES 不可行?
  • @Kalle,说得好。我认为@Seva Alekseyev 非常清楚地说明了这一点。使用 ^= 可能很脆弱,但在许多情况下都可以使用。
【解决方案2】:

submember 类编写一个为您切换它的方法?

- (void) toggleMyBOOL {
  self.myBool = !self.myBool;
}

那么你可以这样做:

[objectWithLongishName.memberWithLongishName.submember toggleMyBOOL];

【讨论】:

    【解决方案3】:
    #define NOT(b) (b) = !(b)
    
    NOT(MyBooleanVariableWithAFreakishlyLongName);
    

    或者,如果它是 Objective C++:

    inline void NOT(BOOL &b)
    {
        b = !b;
    }
    

    【讨论】:

      【解决方案4】:

      这是另一个:

      MyBooleanYaddaYadda ^= YES;
      

      这有点脆弱 - 它会破坏旧的 C 代码,这意味着任何非零整数的计算结果都为真。但话又说回来,Apple 框架代码也是如此 - 我在 Cocoa 中遇到过这样的情况,即当作为 BOOL 传递时,非零非一 int 不会产生与传递 YES 相同的效果。

      但是,它不依赖 YES 的位模式 - 仅依赖 NO 为 0。考虑到 C 将整数解释为逻辑值的方式,这几乎是给定的。此外,它不假定 BOOL 的实际数据类型(顺便说一下,在 Cocoa 上是 signed char)。

      Cocoa 中 YES 的位模式是 1。但这不是通用约定。在一些没有内置布尔数据类型的平台上,用作逻辑 TRUE 的整数常量是-1 - 全为一位。如果解释为无符号,则为 0xFFFFFFFF。这种编码有一个模糊的优势,即 bitwize NOT(C 中的 ~ 运算符)等价于逻辑 NOT(C 中的 ! 运算符)。也就是说,~0xFFFFFFFF 为 0,即。 e. ~TRUE 是 FALSE。如果 TRUE 定义为 1,则不会那样工作。

      【讨论】:

      • 从代码清晰的角度来看,它有点失败。乍一看,它看起来像是对 YES 的分配。经常使用,成语可能会脱颖而出,但重新使用它,可能会引起一些头疼。
      • IMO 简洁和缺乏所需的相关基础设施(即宏定义)超过了这个缺点。这就是我接受这个答案的原因。不过,各有各的。
      【解决方案5】:

      使用异或。在 C 中,这是 ^。

      BOOL x = YES;
      x ^= YES; // it's now NO
      x ^= YES; // it's now YES
      x ^= YES; // it's now NO
      x ^= YES; // it's now YES
      x ^= YES; // it's now NO
      x ^= YES; // it's now YES
      ...
      

      编辑:显然有人已经发布了这个。我想我应该说我从未在代码中真正使用过它。 :-)

      【讨论】:

      • 请注意,这是一个按位异或,这意味着如果 x 出于某种原因设置为 1 或 0 以外的任何值,它将始终保持为真,因为您只是在翻转最低位。使用~NO 将用另一个问题替换该问题:您将翻转所有位,结果相同:x 只是在两个真值之间交替。
      • 这就是为什么我将它作为评论发布并说“......但我不会”。 ;) 不过它确实很“整洁”。
      • 如果您设法使 BOOL 等于 1 或 0 以外的值,那么是的,您将遇到问题。但不管怎样,你不会吗?
      【解决方案6】:

      您有一组可爱的答案,专注于将“是”变为“否”或反之亦然,但没有答案触及代码中似乎是架构问题的问题。

      嗯,一些答案。我瞎了。

      也就是说,你有这个:

      objectWithLongishName.memberWithLongishName.submember.myBOOL =
          !(objectWithLongishName.memberWithLongishName.submember.myBOOL);  
      

      这闻起来像是潜在的封装违规。特别是(假设这是一个模型层),这意味着对象子图的连通性被公然暴露——有效地扁平化——该路径的入口点;无论objectWithLongishName 是什么,现在都必须对路径其余部分的物体内部有相当深入的了解。

      通常,您不会沿着关键路径深入模型层以在 Cocoa Bindings 层之外编辑状态(即使这样也有点脆弱)。

      有时这样长的路径确实有意义。在这种情况下,我会留下您上面的 über-verbose 形式,作为一个视觉指示,表明封装正在被故意撕碎。

      【讨论】:

      • @Barry Wark 提到了这个(违反得墨忒耳法则)
      • 实际上,第一个(或第一个)答案(Barry Wark 的答案)提到了这一点。
      猜你喜欢
      • 1970-01-01
      • 2015-02-18
      • 2013-06-09
      • 2013-06-25
      • 2011-07-10
      • 2016-01-10
      • 1970-01-01
      • 2018-10-21
      • 2023-02-06
      相关资源
      最近更新 更多