[feedhenry-dev] Let's talk about Swift: async completion closure

Summers Pittman supittma at redhat.com
Thu Feb 25 14:43:42 UTC 2016


On Thu, Feb 25, 2016 at 5:55 AM, Corinne Krych <corinnekrych at gmail.com>
wrote:

> As we start writing the FH Swift SDK, I'd like to discuss the Swift syntax
> of our API. In this thread, I'd like to focus on how to express async
> completion. Let's see in detail the syntax of FH.init and FH.cloud.
>
> *S0: Swift consuming ObjC sdk*
>
> *Motivation:*
> Swift app consuming our ObjC fh-io-ask will use the automatic conversion.
> Default syntax helloworls-ios template [1].
>
> *API looks like:*
>
>> public class func initWithSuccess(sucornil: ((FHResponse!) -> Void)!,
>> andFailure failornil: ((FHResponse!) -> Void)!)
>> public class func performCloudRequest(path: String!, withMethod
>> requestMethod: String!, andHeaders headers: [NSObject : AnyObject]!,
>> andArgs arguments: [NSObject : AnyObject]!, andSuccess sucornil:
>> ((FHResponse!) -> Void)!, andFailure failornil: ((FHResponse!) -> Void)!)
>
>
> Note the extensive usage of implicit umwrap (the ! mark). As ObjC does not
> have Optional.
> Let's see how we can improve it.
>
> *S1: More iOS standard lib: one completion block/closure*
>
> *Motivation:*
> One completion close to looks like iOS standard lib. For example, if you
> look at [NSURLSession API documentation](
> https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSession_class/#//apple_ref/occ/instm/NSURLSession/dataTaskWithRequest:completionHandler:),
> you can see the usage of `completionHandler`.
>
> *API looks like:*
>
>> public class func `init`(completionHandler: (Response, NSError?) -> Void
>> ) -> Void
>> public class func performCloudRequest(path: String,  method: String,
>> headers: [String:String]?, args: [String: String]?, config: Config =
>> Config(), completionHandler: (Response, NSError?) -> Void) -> Void
>
>
> Note the back tick around init as init is a reserved keyword in Swift.
>
> *API usage:*
>
>> FH.setup(config, completionHandler: { (resp: Response, err: NSError?) ->
>> Void  in
>>    if (err != nil) {
>>      FH.performCloudRequest("/hello",  method: "POST", headers: nil,
>> args: nil, config: config, completionHandler: {(resp: Response, err:
>> NSError?) -> Void  in
>>         // Do something
>>       })
>>    } else {
>>      // Error in FH.init
>>    }
>> })
>
>
> *Pro:*
> Easy to use, close to ObjC API
> *Con:*
> Error code used, no usage os error handling
>
> *S2: More Swift 2: Using Error handling for async, closure wrapper*
>
> *Motivation:*
> Make use of try/catch instead of NSError to looks more Swift2.
> Refer to this excellent article:
> http://alisoftware.github.io/swift/async/error/2016/02/06/async-errors/#hacking-it
> or more on wrapper closure on
> http://appventure.me/2015/06/19/swift-try-catch-asynchronous-closures/
>
> *API looks like:*
>
>> public class func `init`(completionHandler: (() throws -> Response) ->
>> Void) -> Void
>> public class func performCloudRequest(path: String,  method: String,
>> headers: [String:String]?, args: [String: String]?, config: Config =
>> Config(), completionHandler: (() throws -> Response) -> Void) -> Void
>
>
> *API usage:*
>
>> FH.setup(config, completionHandler: { (inner: () throws -> Response) ->
>> Void in
>>     do {
>>         let result = try inner()
>>         FH.performCloudRequest("/hello",  method: "POST", headers: nil,
>> args: nil, config: config, completionHandler: { (inner: () throws ->
>> Response) -> Void in
>>             do {
>>                 let result = try inner()
>>             } catch _ {}
>>         })
>>     } catch _ {}
>> })
>
>
> *Pro:*
> You do/catch your async method call.
>
> *Con:*
> * Not very elegant syntax
> * Wrapper closure feels awkward.
>
> *S3: More trendy: going "Monad"*
>
> *Motivation:*
> Going one step further, we create an enum container Result wich hold
> "future" values
>
> *API loos like:*
>
>> public class func `init`(completionHandler: Result<Response> -> Void) ->
>> Void
>> public class func performCloudRequest(path: String,  method: String,
>> headers: [String:String]?, args: [String: String]?, config: Config =
>> Config(), completionHandler: Result<Response> -> Void) -> Void
>
>
> *API usage:*
>
>> FH.setup(config, completionHandler: { (result: Result<Response>) -> Void
>> in
>>     do {
>>         let response = try result.resolve()
>>         FH.performCloudRequest("/hello",  method: "POST", headers: nil,
>> args: nil, config: config, completionHandler: { (result: Result<Response>)
>> -> Void in
>>             do {
>>                 let result = try result.resolve()
>>             } catch _ {/*ERROR */}
>>         })
>>     } catch _ {/*ERROR */}
>> })
>
>
> *Pro:*
> Modern syntax close to promise/future
>
> *Con:*
> A bit far from the other Java/JS/C# syntax
>
> *Conclusion*
>
> After trying S2, I have to say it's quite awkward, I'd rather stick to S1.
> S3 is really nice but does not fit with other languages API.
> On aside note, I'd also recommand that we should shorten method name ie:
> `performCloudRequest:method:headers:args:completionHandler:` will become
> `cloud:method:headers:args:completionHandler:` to stick closer to
> JavaScript syntax.
>
> In my opinion, S1 is easy route making the ObjC/Swift transition easy.
> This is my point of view, but I'd love to hear from you.
>
>
Might I suggest using events instead?

Sorry for the Java but I'm thinking something like this :

public class SplashScreen extends AppCompatActivity {

    FHClient client = new FHClient();

    @Override
    protected void onStart() {
        super.onStart();
        fhClient.registerEventHandler(this)
        if (!fhClient.isInit()) {
            fhClient.init();
        }
    }

    public void onInit(InitSuccessful event) {
        //Client is initted
    }
    public void onInitError(final InitFailed event) {
        //some kind of init failure.
    }
}


I'm borrowing patterns that Google Play uses in Android proper, and I would
like to see the Android SDK also adopt an event driven model (perhaps using
an event bus mechanism)


> _______________________________________________
> feedhenry-dev mailing list
> feedhenry-dev at redhat.com
> https://www.redhat.com/mailman/listinfo/feedhenry-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/feedhenry-dev/attachments/20160225/e96e4bbc/attachment.htm>


More information about the feedhenry-dev mailing list