How to use block/closure in swift

2019-06-20 06:19发布

问题:

In one of my app I have used block for webservice calling and getting response. Now I want to write this app in swift, but I am getting trouble to use blocks/Closure in Swift. Here is my objective C code which I want to migrate in swift:

calling a class method of Communicator

[[Communicator sharedInstance]callWebService:WS_LOGIN withMethod:POST_METHOD andParams:params showLoader:YES completionBlockSuccess:^(id obj) {
   //Do play with data
}completionBlockFailiure:^(id obj) {
   //Show alert with error
}];

in communicator class

-(void)callWebService:(NSString *)serviceName withMethod:(NSString *)methodName andParams:(NSDictionary *)params showLoader:(BOOL)showLoader completionBlockSuccess:(void (^)(id))aBlock completionBlockFailiure:(void (^)(id))aFailBlock
{
   if (showLoader) {
   // show loader
   }
   [self performRequestWithServiceName:serviceName method:methodName andParams:params successblock:aBlock failureblock:aFailBlock];
}

- (void)performRequestWithServiceName:(NSString *)serviceName method:(NSString*)methodName andParams:(NSDictionary*)params
                 successblock:(void (^)(id obj))successBlock
                 failureblock:(void (^)(id obj))failBlock {
   if(callSuceess){
      successBlock(@"Success");
   }else{
      successBlock(nil);
   }
}

回答1:

For Swift. Use AnyObject for id objc type.

func callWebservice (serviceName: String, withMethod method: String, andParams params: NSDictionary, showLoader loader: Bool, completionBlockSuccess aBlock: ((AnyObject) -> Void), andFailureBlock failBlock: ((AnyObject) -> Void)) {
    if loader {
        // Show loader
    }

    performRequestWithServiceName(serviceName, method: method, andParams: params, success: aBlock, failure: failBlock)
}

func performRequestWithServiceName(serviceName: String, method methodName: String, andParams params: NSDictionary, success successBlock: ((AnyObject) -> Void), failure failureBlock: ((AnyObject) -> Void)) {
    if callSuceess {
        successBlock("Success")
    }else {
        successBlock(nil)
    }
}

UPDATE: An example when you want call web service. See code below

callWebservice("your-service-name", withMethod: "your-method", andParams: ["your-dic-key": "your dict value"], showLoader: true/*or false*/, completionBlockSuccess: { (success) -> Void in
    // your successful handle
}) { (failure) -> Void in
    // your failure handle
}


回答2:

Your code might look like this:

func callWebService(serviceName: String, method: String, params: [String : AnyObject], showLoader: Bool, success: (responseObject: AnyObject) -> Void, failure: (responseObject: AnyObject) -> Void) {
    if showLoader {
        // show loader
    }

    performRequest(serviceName, method: method, params: params, success: success, failure: failure)
}

func performRequest(serviceName: String, method: String, params: [String : AnyObject], success: (responseObject: AnyObject) -> Void, failure: (responseObject: AnyObject) -> Void) {

}

I replaced NSDictionary with [String : AnyObject]. If you can replace any of the uses of AnyObject with more specific types, your code will be cleaner and more stable.



回答3:

In the communicator class the method that cals the webservice would be defined something like this depending on the type of object you want to return

func performRequest(serviceName: NSString, methodName: NSString,paramaters:NSDictionary, successblock: (String)->(), failureBlock: () -> ()) {
    if(callSuccess) {
        successblock("Success")
    } else {
       failureBlock() 
}

We define the success and failure blocks types as by their function signatures in the case above success is defined as a method that takes a string as an input parameter and returns nothing so we can then call successBlock passing in a string. The failure block is defined above as a block that takes no parameters and returns nothing.

To call this method

func callWebService(serviceName: NSString, method: NSString and parameters: NSDictionary, showLoader: Bool, completionBlockSuccess:(String) -> (), completionBlockFailiure:() -> ()) {
    if (showLoader) {
    // show loader
    }
    performRequest(serviceName: serviceName, methodName: method, parameters, successBlock:completionBlockSuccess, failureBlock: completionBlockFailiure)
}

Finally to call this

Communicator.sharedInstance().callWebService(serviceName: WS_LOGIN , method: POST_METHOD and parameters: params, showLoader: true, completionBlockSuccess:{ returnedString in

     //Do play with data

}, completionBlockFailiure:{ 

    //Show alert with error

})

For the completion block we define a variable returnedString to allow us to manipulate that input parameter (in the above example it would be the string "Success"). I assume your data is not just returning a string though so you will probably need to play around with they type depending on what your service returns.

Also here I tried to match your method signatures by using NSString and NSDictionary though depending on your needs the Swift equivalents String and [String: AnyObject] could be more appropriate.



回答4:

For Swift Closures we have to use ( ) -> ( )

For example:

func yourFunction(success: (response: AnyObject!) -> Void, failure: (error: NSError?) -> Void) {

}

You can call it as:

yourFunction({(response) -> Void in
    // Success
}) { (error) -> Void in
    // Handle Errors
}

Hope it will help you to create Closures with your requirements.



回答5:

func processingWithAnyObject(input: String, completion: @escaping (_ result: AnyObject) -> Void) {
    ...
    completion(response.result.value! as AnyObject)
}

processingWithAnyObject("inputString") {
    (result: AnyObject) in
    print("back to caller: \(result)")
}