【问题标题】:Objective-C Block Property with Xcode code completion带有 Xcode 代码完成的 Objective-C 块属性
【发布时间】:2012-02-25 15:31:24
【问题描述】:

是否可以在 Xcode 4 中定义一个 Objective-C 块属性但仍具有完整代码完成功能?

如果我使用 typedef 来定义块:

typedef void (^CompletionBlock)(MyObject *myObj);

然后定义属性:

@property (nonatomic, copy) CompletionBlock completionBlock;

然后@synthesize 调用setter 时我没有获得完整代码完成的属性。 Xcode 将使用 typedef,因此,代码完成不使用带有块参数的完整块语法,它使用 typedef。

如果我在标头中定义一个使用完整块语法而不是 typedef 的方法原型:

@property (nonatomic, copy) void (^completionBlock)(MyObject *myObj);

然后我使用@synthesize,提供的 setter 接近于使用完整的代码完成语法,但至关重要的是它忽略了参数名称:

[self setCompletionBlock:(void (^)(MyObject *)) { ... }

最后,如果我尝试@synthesize然后重写setter实现或将原型放在标题中:

- (void)setCompletionBlock:(void (^)(MyObject *myObj))completionBlock {...}

发出警告,指出属性类型与访问器类型不匹配。无论我如何尝试修改语法,我都无法同时定义块属性和具有代码​​完成完整语法的设置器。我可以把我的蛋糕也吃掉吗?

谢谢!

【问题讨论】:

  • 它提出了这个问题......为什么typedef?为了减少功能和半冗余的代码行?也许这就是 Apple 的说法……“不要那样做!”??

标签: ios objective-c xcode xcode4 objective-c-blocks


【解决方案1】:

将块作为参数传递给类中的方法时,您可以获得一些漂亮的代码完成。在头文件中,我键入了这样的块

typedef void (^MyCompletionBlock)(id obj1, id obj2);

然后我可以将它用作我在此类头文件中声明的方法的参数。

-(void)doThisWithBlock:(MyCompletionBlock)block;

在m文件中我声明了方法

-(void)doThisWithBlock:(MyCompletionBlock)block {
    NSLog(@"Something");
}

当我去调用它时,我得到了像这样的花哨的代码完成。

希望这能回答你的问题。

【讨论】:

  • 不幸的是,当您使用 typedef 块类型定义 @property 并使用手动定义的 setter 方法或生成的 @synthesize'd setter 时,行为不同并且 Xcode 不使用完整的块语法。
  • 我遇到了同样的问题。从 Xcode 4.3.2 (4E2002) 开始,这是正确的。您必须在接口部分中使用 typedef 和显式方法声明。当您想要获得完整的代码完成时,既不能使用属性也不能定义没有 typedef 块的方法。
  • 在 Xcode 中仍然是这样的(4 后面的数字,如果你敢的话,请编辑我)。啊!
  • 公认的解决方案似乎仍然是实现所需行为的最简单方法,因为它只需要在接口中声明 setter 方法。
  • 我认为这根本没有回答他的问题。突出显示应出现在每个单独的属性上,而不是整个参数集。例如,他想将 id obj1 替换为实际值。您的代码不允许您这样做;相反,它会返回您已经传递给完成块的值,以便您可以在块中使用它们。要将值放入 obj1 和 obj2,您必须调用 block(, );这违背了目的。
【解决方案2】:

我不知道完整的代码完成,但您可以使用代码 sn-ps 来获得类似代码完成的行为,并且您可以在代码 sn-ps 中使用占位符。 希望对你有帮助

【讨论】:

    【解决方案3】:

    如果您愿意在您的类界面中添加一行额外的代码,您绝对可以拥有自己的蛋糕并吃掉它。

    首先,使用 typedef 定义块并创建一个属性,就像您在问题中所做的那样:

    typedef void (^CompletionBlock)(MyObject *myObj);
    
    ...
    
    @property (nonatomic, copy) CompletionBlock completionBlock;
    

    接下来,正如 MobileOverload 在他的回答中指出的那样,我们知道如果在独立方法声明中使用,Xcode 会为 typedef 的块提供正确的代码完成。所以,让我们为completionBlock的setter添加一个显式声明:

    - (void)setCompletionBlock:(CompletionBlock)completionBlock;
    

    调用时,此方法解析为属性声明的 setter 方法。但是,因为我们在类接口中明确定义了它,Xcode 会看到它并应用完整的代码完成。

    因此,如果您包含所有这三行,您应该会得到所需的结果。这种行为显然是 Xcode 的一个缺点,因为在 @property 语句中定义的 setter 没有理由与自己定义的相同方法具有不同的代码完成。

    【讨论】:

    • 这行得通,谢谢!我会为此提交一份错误报告,希望我们以后不需要显式方法声明。
    • 如果我将显式设置器声明添加到我的接口文件,我会收到一个项目警告,指出我的实现不完整。如果我在接口中声明了这个setter,那么我需要在.m中实现它吗?
    • 只有在您未声明该属性或该属性定义的设置器与您明确声明的定义不同时,您才应该收到该警告。
    • 为带有块的属性显式添加设置器就可以了。
    【解决方案4】:

    好的,所以我想出了一种权宜之计,不会导致警告/错误... 并且实际上使事情更容易阅读/更短类型等。

    用我们的“缩写”定义一个宏,然后在属性声明中使用完整的格式...

    #define TINP NSString*(^)(NSString *typed, const char *raw)
    @interface ....
    @property (copy) NSString*(^termDidReadString)(NSString *typed, const char *raw);
    

    随后..然后您可以引用那种“类型”的论点,等等......

    + (void)addInputBlock:(TINP)termDidReadString;
    

    瞧……您的代码不仅会更简洁!!但是代码完成会起作用,就像一个魅力......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-17
      • 2010-11-14
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      • 2010-09-08
      • 1970-01-01
      相关资源
      最近更新 更多