iOS RubyMotion 的 一个深坑

serco · 2015年05月21日 · 最后由 serco 回复于 2015年05月22日 · 7865 次阅读

项目中刚好用到 objective-c 的一个开源项目 Masonry 示例代码如下

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(superview).with.insets(padding);
}];

用 RubyMotion 和 motion-cocoapods 安装

Motion::Project::App.setup do |app|
  app.pods do
    pod 'Masonry'
  end
end

调用

label.mas_makeConstraints(lambda { |make| # Line 24
      make.center.equalTo(superview)
})

一切看上去都很美好,直到现实给了我一耳光

*** Terminating app due to uncaught exception 'ArgumentError', reason: 'guess_view_controller.rb:24:in `block in viewDidLoad': wrong number of arguments (1 for 0) (ArgumentError)

那就检查下到底哪里出了问题

p make.center.method('equalTo').arity # return 0

妹啊,为啥跟文档说的不一样的。。。 看完源码才知道。。。 equalTo返回的是个 block,而 objective-c 的 block 就是 TM 的直接调用的。。。

- (MASConstraint * (^)(id))equalTo {
    return ^id(id attribute) {
        return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
    };
}

好吧,改过来就好了

label.mas_makeConstraints(lambda { |make| # Line 24
      make.center.equalTo.call(superview)
})

本来这只是个小事情,可是难道以后 Objective-C 的库,类似的情况我都要去翻下源码才能确定是不是这个问题嘛。。。 累觉。。还是爱

如果文档有错应该给他们提 issue。

#1 楼 @rei 对于 Objective-C 用户来说,文档没错,API 文档没必要解释内部实现。 不管是 equalTo 是一个接受一个参数的方法还是返回一个可以接受一个参数的 block,调用方式都是equalTo(someArgument)

但是,RubyMotion 用户来使用 Objective-C 的开源库,有时就很坑,必须去看下源码才知道这是个直接的方法还是只是返回个 block

你误解了 Objective-C 的语法,把它和 C++ 的语法混淆了

foo.equalTo(bar)

其实是下面的语法糖 (记住,objective-C 的点语法是 getter 的语法糖而不能代替带参数的方法!! ):

[foo equalTo](bar)

所以对应的 Ruby 是 foo.equalTo.(bar) 或者 foo.equalTo[bar] 或者 foo.equalTo.call bar

假如 equalTo 需要一个参数,在 Objective-C 中就只能这么写:

[foo equalTo: bar]

#3 楼 @luikore 对,之前条件反射一样把 foo.equalTo(bar)当成了单参数方法的调用。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号