1

My goals is to return a value when Alamofire is ready with his tasks. Below script is part of my singleton, that will be called by my viewController. I have looked around and there are examples of where a completion handler is implemented with Alamofire.

Singleton:

func getPeople() -> [Person] {
        
    var persons:[Person] = []
        
    Alamofire.request(requestURL, method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in
        if let json = response.result.value as? Dictionary<String, Any> {
                
            for field in json {
                // Reference to person class
                let person = Person()
                    
                // Properties will be fill in
                ...
                ...

                // Add properties to the person object
                persons.append(person)
                    
           }

        }
            
    }
    return persons
        
}

Viewcontroller

I will call above function in my ViewController.swift and add it to an array of People.

var persons = [Person]()

override func viewDidLoad() {
    super.viewDidLoad()
    
    let request = requestHandler()
    self.persons = request.getPeople()
}

Because Alamofire will be asynchroon, I don't get returned the array of persons. How do I return the value persons to a function that is called from my viewcontroller.swift? I am using Swift 3.

halfer
  • 19,824
  • 17
  • 99
  • 186
Caspert
  • 4,271
  • 15
  • 59
  • 104

1 Answers1

1

You should use closures for this purpose:

func getPeople(success: (([Person])->Void)?, failure: ((Error)->Void)?) {
    //create Alamofire request
    //if everything was fine call success block with people array passed into it
    //if failure occurred, call failure block with error.
    //In any case you must call either `success` of `failure` here
}

Usage:

ServerManager.sharedInstance.getPeople(
            success: { people in
                //use people here, update UI if needed
            },
            failure: { error in
                //show an error
        })

You can read more about closures in swift here, but I will leave some explanation about your particular case:

Basically, (([Person])->Void)? is a type of the closure. It means that the closure will accepts an array of Person objects and is returning nothing (Void). ? in the end means that it's an optional parameter, so you can pass nil when you call getPeople function if you're not interested in the callback at all.

The same about ((Error)->Void)? failure closure. If you call it, you must pass an Error object to describe what actually went wrong.

Why you closures should be optional?

For example, you have an endpoint for sending user's location to the server. Sometimes you will want to run some code after request is finished and sometimes you don't care if it fails or not (you're just sending the coordinates in background). If you don't need a callback, you can pass an empty closure or nil. In fact there is nothing wrong in using empty closure like { _ in } but it's a bit cleaner if you pass nil. You can meet optional closures in some UIKit methods as well:

present(_:animated:completion:)

animate(withDuration:animations:completion:)

P.S. You can also design your method in such way that it has only one completion callback with two optionals:

func getPeople(completionHandler: (([Person]?, Error?)->Void)?) {}

Personally I prefer two closures because it's more evident and readable, though it's a matter of taste.

alexburtnik
  • 7,661
  • 4
  • 32
  • 70
  • Can you tell me what is happening with succes and failure parameters? I know that succes will be called if the request is successfully and failure when it failures, but the use of the `(([People])->Void)?` and `((Error)->Void)?` isn't clear to me right know.. – Caspert Oct 25 '16 at 13:01
  • @Caspert I've just updated the answer with more details about closures. – alexburtnik Oct 25 '16 at 13:12
  • Thanks for the explanation. The only thing what I doesn't understand is, way should you pass nil in the closure? Do you have an example for that. Because Void will return you by default nothing if I understand it? – Caspert Oct 25 '16 at 17:36
  • @Caspert: Check the update, I've added a some details about optional closures. – alexburtnik Oct 25 '16 at 17:54
  • Thank you for your time and explanation. It's a lot clearer for me know! I will try it out. Thanks! – Caspert Oct 25 '16 at 18:11