This little post aims to help you to translate Objective-C Blocks into Ruby blocks. Let's start by taking a look at few examples of iOS API call where blocks are used for animations and enumeration
Im Rubymotion and MacRuby you can use all the Ruby Lambda syntaxes that are:
block = lambda { |param| ... }
block = lambda do |param|
...
end
block = -> param { ... }
block = -> param do
...
end
block = Proc.new{ |param| ... }
block = Proc.new do |name|
....
end
block = proc { ... }
block = proc do |name|
...
end
####Objective-C Blocks with no arguments
[UIView animateWithDuration:0.2
animations:^{view.alpha = 0.0;}]
this is how the Method looks like: __ + animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations__, this method takes two arguments duration and animations, where animations where animations is block (lambda) that takes no arguments
UIView.animateWithDuration(0.2, animations:-> { view.alpha = 0.0 })
####Objective-C Blocks with one argument
[UIView animateWithDuration:0.2
animations:^{view.alpha = 0.0;}
completion:^(BOOL finished){ [view removeFromSuperview]; }];
this is how the Method looks like: animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion, this method takes three arguments duration, animations and completion where animations and completion are blocks. the animations blocks does not take an argument, but completion does.
# we use the Ruby 1.9 Lambda sytax
UIView.animateWithDuration(0.2,
animations:-> { view.alpha = 0.0 },
completion:-> finished { view.removeFromSuperview })
Since we don't use the finished variable, we could also do this:
# we use the Ruby 1.9 Lambda sytax
UIView.animateWithDuration(0.2,
animations:-> { view.alpha = 0.0 },
completion:-> _ { view.removeFromSuperview })
####Objective-C Blocks with two arguments
NSSet *aSet = [NSSet setWithObjects: @"X", @"Y", @"Z", @"Pi", nil];
NSString *aString = @"z";
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop){
if ([obj localizedCaseInsensitiveCompare:aString]==NSOrderedSame) {
NSLog(@"Object Found: %@", obj);
*stop = YES;
}
} ];
The method enumerateObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block of NSSet is an enumeration method that takes a block with two arguments this is how it would look like in Ruby
the_set = NSSet.setWithObjects("X", "Y", "Z", "Pi", nil)
the_str = "z"
the_set.enumerateObjectsUsingBlock(lambda do |obj, stop|
if obj.localizedCaseInsensitiveCompare(the_str) == NSOrderedSame
NSLog("Object Found: %@", obj)
stop.assign(true)
end
end)
####Objective-C Blocks with three arguments
The NSArray method (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
NSArray *anArray = [NSArray arrayWithObjects:@"A", @"B", @"D", @"M", nil];
NSString *string = @"c";
[anArray enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){
if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
NSLog(@"Object Found: %@ at index: %i",obj, index);
*stop = YES;
}
} ];
the Ruby Version
the_array = ["A", "B" ,"D", "C", "M"]
the_str = "c"
the_array.enumerateObjectsUsingBlock(-> obj, index, stop {
if (obj.localizedCaseInsensitiveCompare(the_str) == NSOrderedSame)
NSLog("Object Found: %@ at index: %@", obj, index)
stop.assign(true)
end
})
Now let's get crazy :-), you will be able to explain it yourself
strings = ["string 1", "String 21", "string 12", "String 11", "String 02"]
comparison_opts = NSCaseInsensitiveSearch | NSNumericSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch
current_locale = NSLocale.currentLocale
result = strings.sortedArrayUsingComparator(lambda do |first, second|
first_range = NSMakeRange(0, first.length)
first.compare(second, options:comparison_opts, range:first_range, locale:current_locale)
end
)
NSLog("finderSortArray: %@", result)