Cegah penutupan agar tidak berjalan hingga penutupan lainnya selesai

Berikut adalah kode untuk dua penutupan dalam dua penekanan tombol IBAction yang berbeda. Hasil yang diinginkan adalah menekan tombol untuk menghidupkan/mematikan LED, kemudian mengakses sensor cahaya dan membaca nilai cahaya setelah perubahan status LED.

Apa yang terjadi adalah kondisi balapan di mana fungsi getVariable berjalan dan kembali sebelum callFunction mengimplementasikan perubahan. Hasilnya adalah nilai yang ditampilkan di getLightLabel.text adalah nilai dari kondisi sebelumnya, bukan kondisi saat ini.

Pertanyaan saya adalah bagaimana cara menulis ulang kode di bawah ini sehingga myPhoton!.getVariable tidak dijalankan sampai myPhoton!.callFunction telah kembali (menyelesaikan tugasnya).

Saya telah mencoba menempatkan getVariable di dalam callFunction, sebelum dan sesudah } menutup if (kesalahan == nihil), tetapi hasilnya sama dengan kode yang ditampilkan di sini.

@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"
            }
        }
    })

}

Berikut adalah komentar dan kode callFunction dari file .h. SDK ini ditulis dalam Objective C. Saya menggunakannya di Swift dengan file header penghubung.

/**
 *  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;
 */

Ini kode file .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);
    }];

}

person Bendrix    schedule 18.06.2015    source sumber
comment
Apakah Anda yakin masalah Anda bukan pada kode itu sendiri? Di kedua callFunctions, Anda tampaknya menggabungkan kode untuk mendefinisikan suatu fungsi dan memanggil salah satunya - Anda memanggil myPhoton!.callFunction(...) tetapi Anda juga memiliki kode dalam tanda kurung {...} setelah Anda melewatinya semua argumenmu.   -  person dunnmifflsys    schedule 18.06.2015
comment
@dunnmifflsys inilah yang dapat Anda lakukan dengan penutupan sebagai parameter terakhir dalam pemanggilan fungsi. foo(blok: {closure}) dapat ditulis foo {closure}. Apa yang saya lewatkan di postingan asli adalah definisi callFunction dan getVariable.   -  person Laurent    schedule 18.06.2015
comment
bisakah kami melihat definisi callFunction(_:withArguments:) Anda?   -  person fqdn    schedule 18.06.2015
comment
Lihat perubahan yang dimaksud. Saya menambahkan kode file .h dan .m dari Objective C SDK. Saya menggunakan file header penghubung di Swift untuk mengakses fungsi tersebut. Jika memungkinkan untuk membatasi solusi pada Swift, itu akan lebih disukai.   -  person Bendrix    schedule 18.06.2015


Jawaban (1)


Salah satu solusinya adalah dengan menempatkan penutupan kedua di dalam yang pertama, di mana penutupan pertama mengembalikan dan memberikan nilai Error. Jika tidak ada kesalahan, jalankan penutupan kedua. Itu adalah salah satu cara untuk menggabungkan kedua penutupan secara erat tanpa menggunakan semaphore atau skema pesan lainnya.

Dalam aplikasi ini, masalah yang saya temui tidak dapat diselesaikan di sisi tumpukan IOS/Swift. Cloud API dan uP yang tertanam tidak digabungkan secara erat, sehingga cloud kembali ke IOS dengan penyelesaian sebelum kode fungsi penuh dijalankan pada Particle uP.

Solusi untuk keseluruhan masalah ini sebenarnya terletak pada memodifikasi API cloud atau menambahkan beberapa kode tambahan ke firmware uP untuk memasangkan proses ke aplikasi iOS dengan komunikasi tambahan.

person Bendrix    schedule 13.07.2015