Wait for Delegate callback to finish the function in Swift












1















I have a 3rd-party SDK where architecture is like this:




  • I call a method of the service (lets call it TheirService)

  • Once that method completes, a delegate of that service (lets call it TheirServiceDelegate will receive a notification onSuccess if call succeeds or onFailure if it fails.


The problem with that is that methods of TheirService are dependant on each other, so I end up having a "chain reaction", where each next method of TheirService is called from previous callback.



Note that TheirService is single threaded, and is really picky about previous method to be complete before I can start the next one.



Currently my interactions with the service look like this:



protocol MyClientListener { 
notifyOnFailure()
notifyOnResult(result: SomeObject)
}

class MyClient: TheirServiceDelegate {

static let instance = MyClient()

let myService = TheirService()
var myResult: SomeObject?
var resultListener: MyClientListener

private init() { }

func start(resultListener: MyClientListener) {
self.resultListener = resultListener
myService.initialize()
}

// TheirServiceDelegate method
func onInitializeSuccess() {
myService.bootstrap()
}

// TheirServiceDelegate method
func onBootstrapSuccess() {
myService.login(user, password)
}

// TheirServiceDelegate method
func onLoginSuccess() {
myService.doSomethingUsefulStep1()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep1Success() {
myService.doSomethingUsefulStep2()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep2Success(result: SomeObject) {
// ah, look, now I have some object I actually wanted!
resultListener.notifyOnResult(result)
}
}


I also have to deal with failure case for each of them. And I cannot skip or change the order of steps, which creates some sort of awkward state machine.



Instead i would like to interact with service via logical functions, that complete certain stages of the process from end to end, waiting for results between the steps:



 class MyClient {

static let instance = MyClient()

let myService = MyService()

private init() { }

func connect() throws {
myService.initialize()
// wait for success or failure, throw on failure
myService.bootstrap()
// wait for success or failure, throw on failure
myService.login(user, password)
// wait for success or failure, throw on failure
}

func doSomethingUseful() -> SomeObject {
myService.doSomethingUsefulStep1()
// wait for success or failure, throw on failure
myService.doSomethingUsefulStep2()
// wait for success or failure, throw on failure
// on success, it will get an object it could return
}


Called like this:



try MyClient.instance.connect()
let x = try MyClient.instance.doSomethingUseful()


So is there any way to turn "wait for success or failure" comment into actual code that waits for that single-threaded service to call back? And where a delegate would fit in that case?










share|improve this question























  • What is the TheirService? Like link to their files on GitHub?

    – impression7vx
    Jan 19 at 8:01













  • @impression7vx it's not open source, can't provide a link or their source code (I don't have it, all I have is their API which I access via POD, and instructions how to use it, which result in this chain)

    – Kiril S.
    Jan 21 at 0:30
















1















I have a 3rd-party SDK where architecture is like this:




  • I call a method of the service (lets call it TheirService)

  • Once that method completes, a delegate of that service (lets call it TheirServiceDelegate will receive a notification onSuccess if call succeeds or onFailure if it fails.


The problem with that is that methods of TheirService are dependant on each other, so I end up having a "chain reaction", where each next method of TheirService is called from previous callback.



Note that TheirService is single threaded, and is really picky about previous method to be complete before I can start the next one.



Currently my interactions with the service look like this:



protocol MyClientListener { 
notifyOnFailure()
notifyOnResult(result: SomeObject)
}

class MyClient: TheirServiceDelegate {

static let instance = MyClient()

let myService = TheirService()
var myResult: SomeObject?
var resultListener: MyClientListener

private init() { }

func start(resultListener: MyClientListener) {
self.resultListener = resultListener
myService.initialize()
}

// TheirServiceDelegate method
func onInitializeSuccess() {
myService.bootstrap()
}

// TheirServiceDelegate method
func onBootstrapSuccess() {
myService.login(user, password)
}

// TheirServiceDelegate method
func onLoginSuccess() {
myService.doSomethingUsefulStep1()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep1Success() {
myService.doSomethingUsefulStep2()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep2Success(result: SomeObject) {
// ah, look, now I have some object I actually wanted!
resultListener.notifyOnResult(result)
}
}


I also have to deal with failure case for each of them. And I cannot skip or change the order of steps, which creates some sort of awkward state machine.



Instead i would like to interact with service via logical functions, that complete certain stages of the process from end to end, waiting for results between the steps:



 class MyClient {

static let instance = MyClient()

let myService = MyService()

private init() { }

func connect() throws {
myService.initialize()
// wait for success or failure, throw on failure
myService.bootstrap()
// wait for success or failure, throw on failure
myService.login(user, password)
// wait for success or failure, throw on failure
}

func doSomethingUseful() -> SomeObject {
myService.doSomethingUsefulStep1()
// wait for success or failure, throw on failure
myService.doSomethingUsefulStep2()
// wait for success or failure, throw on failure
// on success, it will get an object it could return
}


Called like this:



try MyClient.instance.connect()
let x = try MyClient.instance.doSomethingUseful()


So is there any way to turn "wait for success or failure" comment into actual code that waits for that single-threaded service to call back? And where a delegate would fit in that case?










share|improve this question























  • What is the TheirService? Like link to their files on GitHub?

    – impression7vx
    Jan 19 at 8:01













  • @impression7vx it's not open source, can't provide a link or their source code (I don't have it, all I have is their API which I access via POD, and instructions how to use it, which result in this chain)

    – Kiril S.
    Jan 21 at 0:30














1












1








1








I have a 3rd-party SDK where architecture is like this:




  • I call a method of the service (lets call it TheirService)

  • Once that method completes, a delegate of that service (lets call it TheirServiceDelegate will receive a notification onSuccess if call succeeds or onFailure if it fails.


The problem with that is that methods of TheirService are dependant on each other, so I end up having a "chain reaction", where each next method of TheirService is called from previous callback.



Note that TheirService is single threaded, and is really picky about previous method to be complete before I can start the next one.



Currently my interactions with the service look like this:



protocol MyClientListener { 
notifyOnFailure()
notifyOnResult(result: SomeObject)
}

class MyClient: TheirServiceDelegate {

static let instance = MyClient()

let myService = TheirService()
var myResult: SomeObject?
var resultListener: MyClientListener

private init() { }

func start(resultListener: MyClientListener) {
self.resultListener = resultListener
myService.initialize()
}

// TheirServiceDelegate method
func onInitializeSuccess() {
myService.bootstrap()
}

// TheirServiceDelegate method
func onBootstrapSuccess() {
myService.login(user, password)
}

// TheirServiceDelegate method
func onLoginSuccess() {
myService.doSomethingUsefulStep1()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep1Success() {
myService.doSomethingUsefulStep2()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep2Success(result: SomeObject) {
// ah, look, now I have some object I actually wanted!
resultListener.notifyOnResult(result)
}
}


I also have to deal with failure case for each of them. And I cannot skip or change the order of steps, which creates some sort of awkward state machine.



Instead i would like to interact with service via logical functions, that complete certain stages of the process from end to end, waiting for results between the steps:



 class MyClient {

static let instance = MyClient()

let myService = MyService()

private init() { }

func connect() throws {
myService.initialize()
// wait for success or failure, throw on failure
myService.bootstrap()
// wait for success or failure, throw on failure
myService.login(user, password)
// wait for success or failure, throw on failure
}

func doSomethingUseful() -> SomeObject {
myService.doSomethingUsefulStep1()
// wait for success or failure, throw on failure
myService.doSomethingUsefulStep2()
// wait for success or failure, throw on failure
// on success, it will get an object it could return
}


Called like this:



try MyClient.instance.connect()
let x = try MyClient.instance.doSomethingUseful()


So is there any way to turn "wait for success or failure" comment into actual code that waits for that single-threaded service to call back? And where a delegate would fit in that case?










share|improve this question














I have a 3rd-party SDK where architecture is like this:




  • I call a method of the service (lets call it TheirService)

  • Once that method completes, a delegate of that service (lets call it TheirServiceDelegate will receive a notification onSuccess if call succeeds or onFailure if it fails.


The problem with that is that methods of TheirService are dependant on each other, so I end up having a "chain reaction", where each next method of TheirService is called from previous callback.



Note that TheirService is single threaded, and is really picky about previous method to be complete before I can start the next one.



Currently my interactions with the service look like this:



protocol MyClientListener { 
notifyOnFailure()
notifyOnResult(result: SomeObject)
}

class MyClient: TheirServiceDelegate {

static let instance = MyClient()

let myService = TheirService()
var myResult: SomeObject?
var resultListener: MyClientListener

private init() { }

func start(resultListener: MyClientListener) {
self.resultListener = resultListener
myService.initialize()
}

// TheirServiceDelegate method
func onInitializeSuccess() {
myService.bootstrap()
}

// TheirServiceDelegate method
func onBootstrapSuccess() {
myService.login(user, password)
}

// TheirServiceDelegate method
func onLoginSuccess() {
myService.doSomethingUsefulStep1()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep1Success() {
myService.doSomethingUsefulStep2()
}

// TheirServiceDelegate method
func onDoSomethingUsefulStep2Success(result: SomeObject) {
// ah, look, now I have some object I actually wanted!
resultListener.notifyOnResult(result)
}
}


I also have to deal with failure case for each of them. And I cannot skip or change the order of steps, which creates some sort of awkward state machine.



Instead i would like to interact with service via logical functions, that complete certain stages of the process from end to end, waiting for results between the steps:



 class MyClient {

static let instance = MyClient()

let myService = MyService()

private init() { }

func connect() throws {
myService.initialize()
// wait for success or failure, throw on failure
myService.bootstrap()
// wait for success or failure, throw on failure
myService.login(user, password)
// wait for success or failure, throw on failure
}

func doSomethingUseful() -> SomeObject {
myService.doSomethingUsefulStep1()
// wait for success or failure, throw on failure
myService.doSomethingUsefulStep2()
// wait for success or failure, throw on failure
// on success, it will get an object it could return
}


Called like this:



try MyClient.instance.connect()
let x = try MyClient.instance.doSomethingUseful()


So is there any way to turn "wait for success or failure" comment into actual code that waits for that single-threaded service to call back? And where a delegate would fit in that case?







swift






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 18 at 23:53









Kiril S.Kiril S.

5,64352143




5,64352143













  • What is the TheirService? Like link to their files on GitHub?

    – impression7vx
    Jan 19 at 8:01













  • @impression7vx it's not open source, can't provide a link or their source code (I don't have it, all I have is their API which I access via POD, and instructions how to use it, which result in this chain)

    – Kiril S.
    Jan 21 at 0:30



















  • What is the TheirService? Like link to their files on GitHub?

    – impression7vx
    Jan 19 at 8:01













  • @impression7vx it's not open source, can't provide a link or their source code (I don't have it, all I have is their API which I access via POD, and instructions how to use it, which result in this chain)

    – Kiril S.
    Jan 21 at 0:30

















What is the TheirService? Like link to their files on GitHub?

– impression7vx
Jan 19 at 8:01







What is the TheirService? Like link to their files on GitHub?

– impression7vx
Jan 19 at 8:01















@impression7vx it's not open source, can't provide a link or their source code (I don't have it, all I have is their API which I access via POD, and instructions how to use it, which result in this chain)

– Kiril S.
Jan 21 at 0:30





@impression7vx it's not open source, can't provide a link or their source code (I don't have it, all I have is their API which I access via POD, and instructions how to use it, which result in this chain)

– Kiril S.
Jan 21 at 0:30












0






active

oldest

votes











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54262858%2fwait-for-delegate-callback-to-finish-the-function-in-swift%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54262858%2fwait-for-delegate-callback-to-finish-the-function-in-swift%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Liquibase includeAll doesn't find base path

How to use setInterval in EJS file?

Petrus Granier-Deferre