Skip to content
junzhan edited this page Jan 13, 2017 · 3 revisions

convert Lua function to OC block

As we know that OC block is a NSObject, and block is corresponding to WaxFunction in wax, so if we know the block's arguments type, we can structure the block.
In armv7/i386, arguments's address in stack is simple, and char,int,BOOL,pointer,id can be treated as int, so we can use variable arguments function to structure a block. (see wax_block_transfer.m) like:

- (LongLong (^)(int p, ...))luaBlockReturnLongLongWithFirstIntParamTypeEncoding:(NSString *)paramsTypeEncoding{
    return [[^LongLong(int q, ...){
        LUA_BLOCK_CALL_ARM32_RETURN_BUFFER(paramsTypeEncoding, LongLong, q);
    } copy] autorelease];
}

In arm64/x86_64, things become harder, but some we treat char,int,BOOL,pointer,id,long as longlong, and treat float,double as double, so can generate a block pool with 510 functions to support block with maximum 7 different kind arguments(is't enough?). (see wax_block_transfer_pool.m)

  • you can use toblock(luaFunction, typeArray) to convert Lua function to OC block. The first item in typeArray must be the return value type(except block that return void and no arguments). (toblock is package of luaBlockWithParamsTypeArray, see lib/stdlib/ext/block.lua)
  • void block, return void block
	UIView:animateWithDuration_animations_completion(1, 
		toblock(
			function()
				label:setCenter(CGPoint(300, 300))
			end
		),
		toblock(
			 	function(finished)
					print('lua animations completion ' .. tostring(finished))
				end
		,{"void", "BOOL"})-- return void
	)
  • - (void)testReturnIdWithFirstIdBlock:(id(^)(id aFirstId, BOOL aBOOL, int aInt, NSInteger aInteger, float aFloat, CGFloat aCGFloat, id aId))block
local res = self:testReturnIdWithFirstIdBlock(
    toblock(
        function(aFirstId, aBOOL, aInt, aInteger, aFloat, aCGFloat, aId)
            print("lua aFirstInt")
            return "123"
        end
        , {"id", "id", "BOOL", "int", "NSInteger" , "float" , "CGFloat" , "id" })
    )
  • avoid retain cycle use block just once
--OC block void (^)(UIViewController * sourceViewController, UIWebView * webView);
local weakSelf = self--temp self
self:setMyblock(
toblock(
    function(sourceViewController, webView)
        -- print("lua sourceViewController")
        print(string.format("lua sourceViewController=%s webView=%s self.price=%s", tostring(sourceViewController), tostring(webView), tostring(weakSelf:price())))
        weakSelf = nil--make it empty
    end
    , {"void", "id", "id"})
)

use block more than once

local weak = {}
b = {__mode = "v"}
setmetatable(weak, b)
weak.self = self

toblock(
	function(sourceViewController, webView)
		-- print("lua sourceViewController")
		print(string.format("lua sourceViewController=%s webView=%s self.price=%s", tostring(sourceViewController), tostring(webView), tostring(weakSelf:price())))
		weak.self:xxx()
	end
	), {"void", "id", "id"})
)

more example in AutoTest

call OC block in Lua

call block like Lua function

--OC block void (^)())block
block()

--or call it like this 
luaCallBlockWithParamsTypeArray(block, {"void"});


--OC block void (^)(NSString * code, NSDictionary * responseData))response
block("abcd", {k1="v1", k2="v2"})

--or call it like this 
luaCallBlockWithParamsTypeArray(block, {"void","id", "id"}, str, {k1="v1", k2="v2"})


--OC block CGFloat(^)(CGFloat aFirstCGFloat, BOOL aBOOL, int aInt, NSInteger aInteger, float aFloat, CGFloat aCGFloat, id aId))block

local res = block(TEST_VALUE_CGFLOAT, TEST_VALUE_BOOL, TEST_VALUE_INTEGER,TEST_VALUE_CGFLOAT)

--or call it like this 
local res = luaCallBlockWithParamsTypeArray(block, {"CGFloat","CGFloat", "BOOL", "NSInteger", "CGFloat"}, TEST_VALUE_CGFLOAT, TEST_VALUE_BOOL, TEST_VALUE_INTEGER,TEST_VALUE_CGFLOAT)

Q:When should use luaCallBlockWithParamsTypeArray?
A:when you want to call a block that is got by toblock

local blockGotBytoblock = toblock(
			function(code, responseData)
				print("lua code=" .. code .. " responseData=" .. tostring(responseData))
			end
		, {"void", "NSString *", "NSDictionary *"})
		
luaCallBlockWithParamsTypeArray(blockGotBytoblock, {"void", "NSString *", "NSDictionary *"},
		"abc", {k1="v1", k2="v2"})

some case in Masonry

if you want to write OC code like this:

    UIView *view = [UIView new];
    [self.view addSubview:view];
    view.backgroundColor = [UIColor greenColor];
    [view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view).offset(200);
        make.left.equalTo(self.view).offset(50);
        make.width.offset(10);
        make.height.offset(10);
    }];

then the Lua code is

    local view = UIView:init()
    self:view():addSubview(view)
    view:setBackgroundColor(UIColor:greenColor())
    view:masUNDERxLINEmakeConstraints(toblock(
      function ( make )
        make:top():equalTo()(self:view()):offset()(200);
        make:left():equalTo()(self:view()):offset()(50);
        make:width():offset()(10);
        make:height():offset()(10);
      end
      ,{"void", "MASConstraintMaker *"}))

Attention: you can't write equalTo(self:view()) or offset(200), because equalTo, offset is not a method which accept arguments, it's a method that returns a block!

more example in AutoTest

Clone this wiki locally