Handling errors in Swift - ios

In my application I need to download a JSON file from the web. I have made a ResourceService class that have a download method as seen below. I use this service in "higher level" services of my app. You can see there are multiple of things that may go wrong during the download. The server could be on fire and not be able to successfully respond at the moment, there could be go something wrong during the moving of the temporary file etc.
Now, there is probably not much a user can do with this other than trying later. However, he/she probably want to know that there was something wrong and that the download or the behaviour of the "higher level" methods could not succeed.
Me as a developer is confused as this point because I don't understand how to deal with errors in Swift. I have a completionHandler that takes an error if there was one, but I don't know what kind of error I should pass back to the caller.
Thoughts:
1) If I pass the error objects I get from the NSFileManager API or the NSURLSession API, I would think that I am "leaking" some of the implementation of download method to the callers. And how would the caller know what kind of errors to expect based on the error? It could be both.
2) If I am supposed to catch and wrap those errors that could happen inside the download method, how would that look like?
3) How do I deal with multiple error sources inside a method, and how would the code that calls the method that may throw/return NSError objects look like?
Should you as a caller start intercepting the errors you get back and then write a lot of code that differentiates the messages/action taken based on the error code? I don't get this error handling stuff at all and how it would look like when there are many things that could go wrong in a single method.
func download(destinationUrl: NSURL, completionHandler: ((error: NSError?) -> Void)) {
let request = NSURLRequest(URL: resourceUrl!)
let task = downloadSession.downloadTaskWithRequest(request) {
(url: NSURL?, response: NSURLResponse?, error: NSError?) in
if error == nil {
do {
try self.fileManager.moveItemAtURL(url!, toURL: destinationUrl)
} catch let e {
print(e)
}
} else {
}
}.resume()
}

First of all this is a great question. Error handling is a specific task that applies to a incredible array of situations with who know's what repercussions with your App's state. The key issue is what is meaningful to your user, app and you the developer.
I like to see this conceptually as how the Responder chain is used to handle events. Like an event traversing the responder chain an error has the possibility of bubbling up your App's levels of abstraction. Depending on the error you might want to do a number of things related to the type of the error. Different components of your app may need to know about error, it maybe an error that depending on the state of the app requires no action.
You as the developer ultimately know where errors effect your app and how. So given that how do we choose to implement a technical solution.
I would suggest using Enumerations and Closures as to build my error handling solution.
Here's a contrived example of an ENUM. As you can see it is represents the core of the error handling solution.
public enum MyAppErrorCode {
case NotStartedCode(Int, String)
case ResponseOkCode
case ServiceInProgressCode(Int, String)
case ServiceCancelledCode(Int, String, NSError)
func handleCode(errorCode: MyAppErrorCode) {
switch(errorCode) {
case NotStartedCode(let code, let message):
print("code: \(code)")
print("message: \(message)")
case ResponseOkCode:
break
case ServiceInProgressCode(let code, let message):
print("code: \(code)")
print("message: \(message)")
case ServiceCancelledCode(let code, let message, let error):
print("code: \(code)")
print("message: \(message)")
print("error: \(error.localizedDescription)")
}
}
}
Next we want to define our completionHandler which will replace ((error: NSError?) -> Void) the closure you have in your download method.
((errorCode: MyAppErrorCode) -> Void)
New Download Function
func download(destinationUrl: NSURL, completionHandler: ((errorCode: MyAppErrorCode) -> Void)) {
let request = NSURLRequest(URL: resourceUrl!)
let task = downloadSession.downloadTaskWithRequest(request) {
(url: NSURL?, response: NSURLResponse?, error: NSError?) in
if error == nil {
do {
try self.fileManager.moveItemAtURL(url!, toURL: destinationUrl)
completionHandler(errorCode: MyAppErrorCode.ResponseOkCode)
} catch let e {
print(e)
completionHandler(errorCode: MyAppErrorCode.MoveItemFailedCode(170, "Text you would like to display to the user..", e))
}
} else {
completionHandler(errorCode: MyAppErrorCode.DownloadFailedCode(404, "Text you would like to display to the user.."))
}
}.resume()
}
In the closure you pass in you could call handleCode(errorCode: MyAppErrorCode) or any other function you have defined on the ENUM.
You have now the components to define your own error handling solution that is easy to tailor to your app and which you can use to map http codes and any other third party error/response codes to something meaningful in your app. You can also choose if it is useful to let the NSError bubble up.
EDIT
Back to our contrivances.
How do we deal with interacting with our view controllers? We can choose to have a centralized mechanism as we have now or we could handle it in the view controller and keep the scope local. For that we would move the logic from the ENUM to the view controller and target the very specific requirements of our view controller's task (downloading in this case), you could also move the ENUM to the view controller's scope. We achieve encapsulation, but will most lightly end up repeating our code elsewhere in the project. Either way your view controller is going to have to do something with the error/result code
An approach I prefer would be to give the view controller a chance to handle specific behavior in the completion handler, or/then pass it to our ENUM for more general behavior such as sending out a notification that the download had finished, updating app state or just throwing up a AlertViewController with a single action for 'OK'.
We do this by adding methods to our view controller that can be passed the MyAppErrorCode ENUM and any related variables (URL, Request...) and add any instance variables to keep track of our task, i.e. a different URL, or the number of attempts before we give up on trying to do the download.
Here is a possible method for handling the download at the view controller:
func didCompleteDownloadWithResult(resultCode: MyAppErrorCode, request: NSURLRequest, url: NSURL) {
switch(resultCode) {
case .ResponseOkCode:
// Made up method as an example
resultCode.postSuccessfulDownloadNotification(url, dictionary: ["request" : request])
case .FailedDownloadCode(let code, let message, let error):
if numberOfAttempts = maximumAttempts {
// Made up method as an example
finishedAttemptingDownload()
} else {
// Made up method as an example
AttemptDownload(numberOfAttempts)
}
default:
break
}
}

Long story short: yes
... and then write a lot of code that differentiates the
messages/action taken based on the error code?
Most code examples leave the programmer alone about how to do any error handling at all, but in order to do it right, your error handling code might be more than the code for successful responses. Especially when it comes to networking and json parsing.
In one of my last projects (a lot of stateful json server communication) I have implemented the following approach: I have asked myself: How should the app possibly react to the user in case of an error (and translate it to be more user friendly)?
ignore it
show a message/ an alert (possibly only one)
retry by itself (how often?)
force the user to start over
assume (i.e. a previously cached response)
To achieve this, I have create a central ErrorHandler class, which does have several enums for the different types of errors (i.e. enum NetworkResponseCode, ServerReturnCode, LocationStatusCode) and one enum for the different ErrorDomains:
enum MyErrorDomain : String {
// if request data has errors (i.e. json not valid)
case NetworkRequestDomain = "NetworkRequest"
// if network response has error (i.e. offline or http status code != 200)
case NetworkResponseDomain = "NetworkResponse"
// server return code in json: value of JSONxxx_JSON_PARAM_xxx_RETURN_CODE
case ServerReturnDomain = "ServerReturnCode"
// server return code in json: value of JSONxxxStatus_xxx_JSON_PARAM_xxx_STATUS_CODE
case ServerStatusDomain = "ServerStatus"
// if CLAuthorizationStatus
case LocationStatusDomain = "LocationStatus"
....
}
Furthermore there exists some helper functions named createError. These methods do some checking of the error condition (i.e. network errors are different if you are offline or if the server response !=200). They are shorter than you would expect.
And to put it all together there is a function which handles the error.
func handleError(error: NSError, msgType: String, shouldSuppressAlert: Bool = false){
...
}
This method started with on switch statement (and needs some refactoring now, so I won't show it as it still is one). In this statement all possible reactions are implemented. You might need a different return type to keep your state correctly in the app.
Lessons learned:
Although I thought that I have started big (different enums, central user alerting), the architecture could have been better (i.e. multiple classes, inheritance, ...).
I needed to keep track of previous errors (as some are follow ups) in order to only show one error message to the user -> state.
There are good reasons to hide errors.
Within the errorObj.userInfo map, it exits a user friendly error message and a technicalErrorMessage (which is send to a tracking provider).
We have introduced numeric error codes (the error domain is prefixed with a letter) which are consistent between client and server. They are also shown to the user. This has really helped to track bugs.
I have implemented a handleSoftwareBug function (which is almost the same as the handleError but much less cases). It is used in a lot of else-blocks which you normally do not bother to write (as you think that this state can never be reached). Surprisingly it can.
ErrorHandler.sharedInstance.handleSoftwareBug("SW bug? Unknown received error code string was code: \(code)")
How does it look like in code: There are a lot of similar backend network requests where a lot of code looks something like the following:
func postAllXXX(completionHandler:(JSON!, NSError!) -> Void) -> RegisteringSessionTask {
log.function()
return postRegistered(jsonDict: self.jsonFactory.allXXX(),
outgoingMsgType: JSONClientMessageToServerAllXXX,
expectedIncomingUserDataType: JSONServerResponseAllXXX,
completionHandler: {(json, error) in
if error != nil {
log.error("error: \(error.localizedDescription)")
ErrorHandler.sharedInstance.handleError(error,
msgType: JSONServerResponseAllXXX, shouldSuppressAlert: true)
dispatch_async(dispatch_get_main_queue(), {
completionHandler(json, error)
})
return
}
// handle request payload
var returnList:[XXX] = []
let xxxList = json[JSONServerResponse_PARAM_XXX][JSONServerResponse_PARAM_YYY].arrayValue
.....
dispatch_async(dispatch_get_main_queue(), {
completionHandler(json, error)
})
})
}
Within the above code you see that I call a completionHandler and give this caller the chance to customize error handling, too. Most of the time, this caller only handles success.
Whenever I have had the need for retries and other and not so common handling, I have also done it on the caller side, i.e.
private func postXXXMessageInternal(completionHandler:(JSON!, NSError!) -> Void) -> NSURLSessionDataTask {
log.function()
return self.networkquery.postServerJsonEphemeral(url, jsonDict: self.jsonFactory.xxxMessage(),
outgoingMsgType: JSONClientMessageToServerXXXMessage,
expectedIncomingUserDataType: JSONServerResponseXXXMessage,
completionHandler: {(json, error) in
if error != nil {
self.xxxMessageErrorWaitingCounter++
log.error("error(\(self.xxxMessageErrorWaitingCounter)): \(error.localizedDescription)")
if (something || somethingelse) &&
self.xxxMessageErrorWaitingCounter >= MAX_ERROR_XXX_MESSAGE_WAITING {
// reset app because of too many errors
xxx.currentState = AppState.yyy
ErrorHandler.sharedInstance.genericError(MAX_ERROR_XXX_MESSAGE_WAITING, shouldSuppressAlert: false)
dispatch_async(dispatch_get_main_queue(), {
completionHandler(json, nil)
})
self.xxxMessageErrorWaitingCounter = 0
return
}
// handle request payload
if let msg = json[JSONServerResponse_PARAM_XXX][JSONServerResponse_PARAM_ZZZ].stringValue {
.....
}
.....
dispatch_async(dispatch_get_main_queue(), {
completionHandler(json, error)
})
})
}
Here is another example where the user is forced to retry
// user did not see a price. should have been fetched earlier (something is wrong), cancel any ongoing requests
ErrorHandler.sharedInstance.handleSoftwareBug("potentially sw bug (or network to slow?): no payment there? user must retry")
if let st = self.sessionTask {
st.cancel()
self.sessionTask = nil
}
// tell user
ErrorHandler.sharedInstance.genericInfo(MESSAGE_XXX_PRICE_REQUIRED)
// send him back
xxx.currentState = AppState.zzz
return

For any request, you get either an error or an http status code. Error means: Your application never managed to talk properly to the server. http status code means: Your application talked to a server. Be aware that if you take your iPhone into the nearest Starbucks, "your application talked to a server" doesn't mean "your application talked to the server it wanted to talk to". It might mean "your application managed to talk to the Starbucks server which asks you to log in and you have no idea how to do that".
I divide the possible errors into categories: "It's a bug in my code". That's where you need to fix your code. "Something went wrong, and the user can do something about it". For example when WiFi is turned off. "Something went wrong, maybe it works later". You can tell the user to try later. "Something went wrong, and the user can't do anything about it". Tough. "I got a reply from the server that I expected. Maybe an error, maybe not, but something that I know how to handle". You handle it.
I also divide calls into categories: Those that should run invisibly in the background, and those that run as a result of a direct user action. Things running invisibly in the background shouldn't give error messages. (Bloody iTunes telling me it cannot connect to the iTunes Store when I had no interest in connecting to the iTunes Store in the first place is an awful example of getting that wrong).
When you show things to the user, remember that the user doesn't care. To the user: Either it worked, or it didn't work. If it didn't work, the user can fix the problem if it is a problem they can fix, they can try again later, or it's just tough luck. In an enterprise app, you might have a message "call your help desk at xxxxxx and tell them yyyyyy".
And when things don't work, don't annoy the user by showing error after error after error. If you send then requests, don't tell the user ten times that the server is on fire.
There are things that you just don't expect to go wrong. If you download a file, and you can't put it where it belongs, well, that's tough. It shouldn't happen. The user can't do anything about it. (Well, maybe they can. If the storage of the device is full then you can tell the user). Apart from that, it's the same category as "Something went wrong, and the user can't do anything about it". You may find out as a developer what the cause is and fix it, but if it happens with an application out in the user's hands, there's nothing reasonable you can do.
Since all such requests should be asynchronous, you will always pass either one or two callback blocks to the call, one for success and one for failure. I have most of the error handling in the download code, so things like asking the user to turn WiFi on happen only once, and calls may even be repeated automatically if such an error condition is fixed by the user. The error callback is mostly used to inform the application that it won't get the data that it wanted; sometimes the fact that there is an error is useful information in itself.

For consistent error handling, I create my own errors representing either errors returned by the session, or html status codes interpreted as errors. Plus two additional errors "user cancelled" and "no user interaction allowed" if either there was a UI involved and the user cancelled the operation, or I wanted to use some user interaction but wasn't allowed to. The last two errors are different - these errors will never be reported to the user.

I would wrap the errors in your own, but pass the underlying error as a property on your error class (ala C#'s InnerException). That way you are giving consumers a consistent interface, but also providing lower level error detail if required. However, the main reason I would do this is for unit testing. It makes it much easier to mock your ResourceService class and test the code paths for the various errors that could occur.
I don't like the thought of passing back an array of errors, as it adds complexity for the consumer. Instead I would provide an array of InnerException instances. If they are instances of your own error class, they would potentially have their own InnerException's with underlying errors. However, this would probably only make sense if you were doing your own validations where multiple errors might make sense. Your download method will probably have to bail out after the first error encountered.

Related

Error when sending data between connected devices in Game Center

I am working on a local multiplayer, real time game in swift 5. In order to achieve the real time gameplay, I am sending data back and forth between two devices with the function GKMatch.sendData(data:, to:, withDataSendingMethod:). It works fairly inconsistently, regardless of if I use .reliable or .unreliable, however the error it gives me when it is unable to send data is consistent. It is as follow:
2020-07-27 21:07:22.433631-0400 Teacher Brawl[19336:5244039] [ViceroyTrace] [ERROR] AGPSessionRecvFrom:1954 0x103f11600 sack: SEARCH FAILURE SERIAL NUMBER (0000000B) FROM (5682ABEE)...
Where Teacher Brawl is the name of the project.
I was wondering if anyone is able to provide insight as to why I am getting the error, as I do not fully understand it being relatively new to swift and newer to GameKit. The code I am using to send the data is shown below, and it is being called anytime there is a tap on the screen, which in the context of this game is fairly minimal. If you need any further details please let me know, I would be happy to provide them. All help is greatly appreciated as the inconsistency of data sending has stopped any progress I can make for this game. :)
func sendButtons(button: String) {
let sendableString: Data? = button.data(using: .utf8)
do {
try localMatch.send(sendableString!, to: localMatch.players, dataMode: .unreliable)
}
catch {
print("")
}
}
For reference, the variable localMatch is my variable for the GKMatch that was returned when both players joined the game.
This error message is common and shouldn't interfere with your game sending data. My app gets this error but still sends data fine.
If you are sending data to all players, you should use the built in function func sendData(toAllPlayers data: Data, with mode: GKMatch.SendDataMode) throws. You should also send data reliably if it is not being sent very often. For debugging reasons, you might want to print when data is sent and print errors. Here is the full code you can try.
func sendButtons(button: String) {
let sendableString: Data? = button.data(using: .utf8)
do {
try localMatch.sendData(toAllPlayers: sendableString!, with: .reliable)
print("Data sent")
}
catch {
print("Data not sent")
print(error)
}
}
If the data is not sent, check if "Data sent" is printed and check for errors

IOS -Core Data Stacl

My question are as follows:
Will creating a custom enum to handle the coredata errors be the best way to handle errors in this case
If the persistent store container doesn't load or we can't save the context then there is no need to use the app and crashing is the best option correct?
In order to present these error messages to the user, wouldn't I have to adapt UIAlertAction? Which would also mean I would need to register notifications?
By law we have to get permission to send notifications, would it be best to create a whole new file for notification & add the error enum in that file or would it make more sense to have the core data stack class conform to the Notification protocol?
The end goal is to notify the user that either the persistent store wouldn't load or the moc wouldn't save
Thanks for your time in advance!
enum CoreDataError: Error {
// This is my custom Error handling enum
case persistenStore(description: String )
case saveChanges(description: String )
}
func coreDataErrors(throwError: Bool) throws -> CoreDataError {
// This is my Error Handling function
}
class CoreDataStack {
lazy var managedObjectContext: NSManagedObjectContext = {
let container = self.persistentContainer
return container.viewContext
}()
private lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "SafeHouseCDPhotoVault")
container.loadPersistentStores() { storeDescription, error in
if let error = error as NSError? {
fatalError("Unresolved error: \(error), \(error.userInfo)")
}
}
return container
}()
}
/* In almost every app tutorial available we learn to deal with errors using this fatal error logic to speed through the project
*/
extension NSManagedObjectContext {
func saveChanges() {
if self.hasChanges {
do {
try save()
} catch {
fatalError("Error: \(error.localizedDescription)")
}
}
}
}
// Again the demos have us deal with errors using fatal error
I typically use enums for error cases, but I wouldn't name them according to their source. Name them according to how you will will them for recovery or error-handler behavior. If you can't handle them, there's not much point in generating them.
That gets to the second question; if you can't handle a case at all (such as the MOM missing on launch), crashing is about all you can do. I don't like alerts in that case. What's the user going to do with that information? A crash at least will be sent to Apple and you can see it and do something about it.
If the user can do something, then absolutely provide an error. If there is any hope that the error is transitory (such as a save failure, which may be due to a full disk), then maybe provide them an error/retry. But on iOS this generally is not worth the trouble and the risk of generating bugs. How are you going to test your error/retry system? If you can't test it, how do you know it's better than crashing? (This isn't an idle question; I once built a crash-catching system that had a bug and caused the crash handler to go into a tight loop and drain the battery rapidly. That's worse than crashing.)
If you're a beginner, then you're probably not in a place to handle uncommon Core Data errors and the best and safest thing you're going to do is crash. Handling these things well is quite complex and difficult to test, and I generally do not recommend it on iOS (macOS is a bit different because write-errors are much more often transitory).
That's up to you.
Exit the app properly with an alert and not by crashing it
Why would you need notifications for showing an alert?
This question makes no sense to me.

Best practice for showing an error Alert

I am having trouble displaying an Alert in case of an Error properly.
My idea is: Everytime I download data from my backend with an completion block, I present an Alert if an error occurs.
query?.findObjectsInBackground(block: { (objects, error) -> Void in
if error != nil {
createAlert(error)
return
} else if let objects = objects {
}
Since I got more than one call in a ViewController at the same time, it may happen to find myself having more than 2 or 3 Alerts presenting at the same time saying e.g. "No Connection to the Internet".
It will constantly reload the Alert and it is a pain in terms of UI.
What is best practice to solve this issue?
My solution idea would be to put everything in a Singleton pattern and make sure no other other Alert is currently displayed.
Are there any better ways?
Instead of using a singleton pattern, you might prefer having an optional property (var noConnectivityAlert) in the class currently responsible for creating the alert.
Instead of the createAlert() method you would have a informUserAboutConnectivity() method.
func informUserAboutConnectivity() {
// If noConnectivityAlert is nil
// the method creates an alert and shows it.
// If the property is NOT nil
// do nothing (since the user is already informed).
}
When the internet connection would come back and then disappear again, some apps in the App Store would show an alert once again.
In that case, when the internet connection comes back you can directly set noConnectivityAlert = nil so that when the connection is lost, things will be handled nicely (a new alert will be created and shown).
By the way, in the iOS SDK, singletons are not used often. There are mostly used for providing a default and most common use case of a class (think of UserDefaults), or (of course) a shared manager/provider.

How to display and recover from API errors in ViewController when using RxSwift

I'm trying to figure out how I can retry an API call at the ViewController layer when dealing with an RxSwift stream. I understand that I can either wrap my errors in an Element or I can return a stream Error. In either case, it's not at all clear how I can "retry" the operation the discretion of the user (e.g. after putting up an alert).
If I wrap the error, how can/should I communicate back "down" to the API layer to attempt a retry? If I don't wrap the error, I have two questions:
1) How can I make the retry conditional on the user's response to the alert? and
2) How can/should I "re-initialize" the stream?
The only thing I've been able to come up with is passing back a "retry subject" with the error and having the view controller indicate the retry request by emitting something on the associated observable (i.e. assign a value to the subject) which would in term be associated with the API stream. That seems awfully convoluted, however.
More generally, I'd appreciate any references to helpful literature on the subject of application error handling with streams/observables. I feel like I have a pretty good grasp of the RxSwift objects and operators and how to handle the "happy path" situation, but it's just not clear to me how to robustly handle errors in the context of continuously running application.
My solution for this is to wrap them to this type Result<AnyObject,ErrorType>
For example, user login scenario
// where API.login() takes the response data and try to map to JSON
// then try to map into Result<JSON,ErrorType>
let loginStream: Result<JSON,ErrorType> = loginTaps.flatMap { API.login() }
.shareReplay()
let loginResponse = loginStream.filter { $0.value != nil }.map { $0.value }
let loginError = loginStream.filter { $0.error != nil }.map { $0.error }
The stream will never be terminated, so no need to re-subscribe them.

Synchronous network calls blocking other calls on startup

I have an App which does hundreds of different network calls (HTTP GET requests) to a REST service. The calls are done from every single page of the app and there are much of them. But there is the requirement that two requests have to be done (on startup or awake) before any other network requests happens. The result of these two requests is some config data which is needed before all other following requests. (this requirement has many reason)
I have one central method for all GET requests. It uses AFNetworking and (of course) asynchronous handlers:
func GET(path: String, var parameters: Dictionary<String, String>? = nil) -> Future<AnyObject!> {
let promise = Promise<AnyObject!>()
manager.GET(path, parameters: parameters, success: { (task: NSURLSessionDataTask!, response: AnyObject!) -> Void in
// some processing...
promise.success(response)
}) { (task: NSURLSessionDataTask!, error: NSError!) -> Void in
// some failure handling...
promise.failure(error)
}
return promise.future
}
The problem now is - how to do this first two calls and block all other calls until those two succeed? The obvious solution would be a semaphore which blocks the thread (not main!) until those two calls arrive successfully but if possible I want to avoid this solution. (because of deadlocks, race conditions, how to do error handling, etc... the usual suspects)
So is there any better solution for this?
The synchronous order basically has to be:
1st call
wait for successful response of 1st call
2nd call
wait or successful response of 2nd call
allow all other calls (async) in any order
I can not do this logic on the upper layers of the app because the GET requests could come from every part of the app, so I would need to rewrite everthing. I want to do it centrally on this single GET request.
Maybe this is also possible with the Promise/Future pattern I already use, any hints are welcome.
Thanks.
There are a couple of approaches to tackle this class of problem:
You can use GCD (as shown in the answer you linked to) using semaphores or dispatch groups.
You can use asynchronous NSOperation custom subclass in conjunction with NSOperationQueue.
Or you can use promises.
But I'd generally suggest you pick one of these three, but don't try to introduce dispatch/operation queue patterns with your existing futures/promises code. People will suggest dispatch/operation queue approaches simply because this is how one generally solves this type of problem (using futures is not gained popular acceptance yet, and there are competing promises/futures libraries out there). But promises/futures is designed to solve precisely this problem, and if you're using that, just stick with it.
On the specifics of the dispatch/operation approaches, I could explain why I don't like the GCD approach and try to convince you to use the NSOperationQueue approach, but that's moot if you're using promises/futures.
The challenge here, though, is that you appear to be using an old version of Thomvis/BrightFutures. The current version takes two types for the generic. So my code below probably won't work for you. But I'll offer it up as as suggestion, as it may be illustrative.
For example, let's imagine that you had a loginURL (the first request), and some second request that you wanted to perform after that, but then had an array urls that you wanted to run concurrently with respect to each other, but only after the first two requests were done. Using 3.2.2 of BrightFutures, it might look like:
GET(loginURL).flatMap { responseObject -> Future<AnyObject!, NSError> in
return self.GET(secondRequestURL)
}.flatMap { responseObject -> Future<Int, NSError> in
return urls.map { self.GET($0) }.fold(0) { sum, _ in sum + 1 }
}.onSuccess { count in
print("\(count) concurrent requests completed successfully")
}.onFailure { error in
print("not successful: \(error)")
}
Judging from your code snippet, you must be using an old version of BrightFutures, so the above probably won't work as written, but hopefully this illustrates the basic idea. Use the capabilities of BrightFutures to manage these asynchronous tasks and control which are done sequentially and which are done concurrently.

Resources