防止关闭运行直到另一个完成

时间:2015-06-18 02:32:00

标签: ios swift closures

以下是两个不同IBAction按钮按下的两个闭包的代码。所需的结果是按钮按下以打开/关闭LED,然后访问光传感器并在LED状态改变后读取光值。

在比赛条件下,getVariable函数在callFunction实现更改之前运行并返回。结果是getLightLabel.text中显示的值是先前条件的值,而不是当前条件。

我的问题是如何重写下面的代码,以便myPhoton!.getVariable直到myPhoton!.callFunction返回(完成其任务)之后才会执行。

我已经尝试将getVariable放在callFunction中,在关闭if之前和之后if(error == nil),但结果与此处显示的代码相同。

@IBAction func lightOn(sender: AnyObject) {
    let funcArgs = [1]
    myPhoton!.callFunction("lightLed0", withArguments: funcArgs) { (resultCode : NSNumber!, error : NSError!) -> Void in
        if (error == nil) {
            self.lightStateLabel.text = "LED is on"
        }
    }
    myPhoton!.getVariable("Light", completion: { (result:AnyObject!, error:NSError!) -> Void in
        if let e = error {
            self.getLightLabel.text = "Failed reading light"
        }
        else {
            if let res = result as? Float {
                self.getLightLabel.text = "Light level is \(res) lumens"
            }
        }
    })



}


@IBAction func lightOff(sender: AnyObject) {
    let funcArgs = [0]
    myPhoton!.callFunction("lightLed0", withArguments: funcArgs) { (resultCode : NSNumber!, error : NSError!) -> Void in
        if (error == nil) {
            self.lightStateLabel.text = "LED is off"
        }
    }
    myPhoton!.getVariable("Light", completion: { (result:AnyObject!, error:NSError!) -> Void in
        if let e = error {
            self.getLightLabel.text = "Failed reading light"
        }
        else {
            if let res = result as? Float {
                self.getLightLabel.text = "Light level is \(res) lumens"
            }
        }
    })

}

这是来自.h文件的callFunction注释和代码。这个SDK是用Objective C编写的。我在Swift中使用它,带有桥接头文件。

/**
 *  Call a function on the device
 *
 *  @param functionName Function name
 *  @param args         Array of arguments to pass to the function on the device. Arguments will be converted to string maximum length 63 chars.
 *  @param completion   Completion block will be called when function was invoked on device. First argument of block is the integer return value of the function, second is NSError object in case of an error invoking the function
 */
-(void)callFunction:(NSString *)functionName withArguments:(NSArray *)args completion:(void (^)(NSNumber *, NSError *))completion;

/*
-(void)addEventHandler:(NSString *)eventName handler:(void(^)(void))handler;
-(void)removeEventHandler:(NSString *)eventName;
 */

这是.m文件代码

-(void)callFunction:(NSString *)functionName withArguments:(NSArray *)args completion:(void (^)(NSNumber *, NSError *))completion
{
    // TODO: check function name exists in list
    NSURL *url = [self.baseURL URLByAppendingPathComponent:[NSString stringWithFormat:@"v1/devices/%@/%@", self.id, functionName]];
    NSMutableDictionary *params = [NSMutableDictionary new]; //[self defaultParams];
    // TODO: check response of calling a non existant function

    if (args) {
        NSMutableArray *argsStr = [[NSMutableArray alloc] initWithCapacity:args.count];
        for (id arg in args)
        {
            [argsStr addObject:[arg description]];
        }
        NSString *argsValue = [argsStr componentsJoinedByString:@","];
        if (argsValue.length > MAX_SPARK_FUNCTION_ARG_LENGTH)
        {
            // TODO: arrange user error/codes in a list
            NSError *err = [self makeErrorWithDescription:[NSString stringWithFormat:@"Maximum argument length cannot exceed %d",MAX_SPARK_FUNCTION_ARG_LENGTH] code:1000];
            if (completion)
                completion(nil,err);
            return;
        }

        params[@"args"] = argsValue;
    }

    [self setAuthHeaderWithAccessToken];

    [self.manager POST:[url description] parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
        if (completion)
        {
            NSDictionary *responseDict = responseObject;
            if ([responseDict[@"connected"] boolValue]==NO)
            {
                NSError *err = [self makeErrorWithDescription:@"Device is not connected" code:1001];
                completion(nil,err);
            }
            else
            {
                // check
                NSNumber *result = responseDict[@"return_value"];
                completion(result,nil);
            }
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error)
    {
        if (completion)
            completion(nil,error);
    }];

}

1 个答案:

答案 0 :(得分:0)

一种解决方案是将第二个闭包放在第一个闭包中,第一个闭包并提供和Error值。如果没有错误,则执行第二个闭包。这是紧密耦合两个闭包而不诉诸信号量或其他消息传递方案的一种方法。

在这个应用程序中,我遇到的问题无法在堆栈的IOS / Swift端解决。云API和嵌入式uP没有紧密耦合,因此在完整功能代码在Particle uP上运行之前,云将返回IOS并完成。

这个整体问题的解决方案实际上在于修改云API或向uP固件添加一些额外的代码,以便通过额外的通信将流程紧密地耦合到IOS应用程序。