While working on an iOS app for a client I came across an interesting language-level bug (or missing feature?) in RubyMotion.
The app has a fancy animation which needed a method on CAMediaTimingFunction called functionWithControlPoints. It turns out that this is one of the places you’ll see a seldom used feature of Objective-C: Nameless Parameters.
A function with Nameless Parameters can be defined like so:
+ (void) sayHello:(NSString *)firstName:(NSString *)lastName;
… and instead of the usual key: value style invocation you can simply omit the keys:
[Greeter sayHello:"Daniel" :"Upton"];
It’s a neat trick, but one that Apple actively discourages and it seems the RubyMotion team aren’t too keen either:
Fortunately they crop up in few places, but unfortunately for us CAMediaTimingFunction is one of them and RubyMotion doesn’t support the syntax (check out the discussion in RM-123).
With a little magic meta-programming you can poke still poke at the method, here’s
what I ended up doing:
# [CAMediaTimingFunction functionWithControlPoints:0.4, :0.0, :0.2, :1.0];
def media_timing_function
signature = NSMethodSignature.signatureWithObjCTypes('@@:ffff')
invocation = NSInvocation.invocationWithMethodSignature(signature)
invocation.target = CAMediaTimingFunction
invocation.selector = 'functionWithControlPoints::::'
[0.4, 0.0, 0.2, 1.0].each_with_index do |point, index|
pointer = Pointer.new('f')
pointer[0] = point
invocation.setArgument(pointer, atIndex: index + 2)
end
invocation.invoke
pointer = Pointer.new('@')
invocation.getReturnValue(pointer)
pointer[0]
end
Eloy suggested a more general purpose workaround in the mentioned ticket.