2015-04-17 3 views
0

Возможно, это может быть непонимание, которое у меня есть в Swift. Я новичок в языке, и мой опыт в Perl, что заставляет меня чувствовать, что быстро действует по-разному.Данные не возвращаются функцией Swift iOS

У меня есть 2 файла. ViewController.swift и APICalls.swift. В viewcontroller у меня есть функция для кнопки. В этой функции я делаю вызов другой функции в APICalls. Когда я это делаю, мой println() в APICalls печатает правильные данные, однако это происходит после моего println() в функции кнопки.

Viewcontroller.swift

@IBAction func buttonStuff(sender: AnyObject) { 

     var api = APICalls() 
     var token:String 

     token = api.TEST("letmein") 

     println("\ntokenDidLOAD = \(token)\n") 

    } 

APICalls.swift

class APICalls { 

    func TEST(command: String) -> (String) { 

     var token:String = "" 

     // Form URL-Encoded Body 
     let bodyParameters = [ 
      "COMMAND":command, 
     ] 

     let encoding = Alamofire.ParameterEncoding.URL 

     // Fetch Request 
     Alamofire.request(.POST, "http://api.com/?v=1", parameters: bodyParameters, encoding: encoding) 
      .validate(statusCode: 200..<300) 
      .responseJSON{(request, response, data, error) in 

       if (error == nil) 
       { 
        let json = JSON(data!) 
        token = json["TOKEN"].string! 
        println("jsonAPI = \(json) \n\n") 
       } 
       else 
       { 
        println("HTTP HTTP Request failed: \(error)") 
       } 

      } 

     return token 

    } 
} 

Вот мой выход

tokenDidLOAD = 

jsonAPI = { 
    "STATUS" : "OK", 
    "TOKEN" : "698798765432134654", 
} 

Я не понимаю, почему 'tokenDidLOAD' печатает первый перед jsonAPI ,

+0

[Разница между синхронным и асинхронным] (http: // stackoverflow.com/q/21122842/468724) –

+0

Вы должны прочитать раздел «Обработка ответов» в Readme Alamofire. В нем явно упоминается асинхронная процедура. –

+0

Похожие вопросы с ответами: http://stackoverflow.com/questions/29377824/swift-alamofire-return-value-is-empty, http://stackoverflow.com/questions/29377824/swift-alamofire-return-value- is-empty, http://stackoverflow.com/questions/25141829/swift-closure-with-alamofire (и еще несколько ...) –

ответ

1

Поскольку запрос, который вы делаете, является асинхронным. Вы сначала возвращаете токен, который еще не присутствует, и только после этого запрос действительно завершен. Вам не нужно получать токен как возвращаемое значение функции TEST. Ваш тест должен быть таким:

func TEST(command: String, completion:(String)->()) { 

var token:String = "" 

// Form URL-Encoded Body 
let bodyParameters = [ 
    "COMMAND":command, 
] 

let encoding = Alamofire.ParameterEncoding.URL 

// Fetch Request 
Alamofire.request(.POST, "http://api.com/?v=1", parameters: bodyParameters, encoding: encoding) 
    .validate(statusCode: 200..<300) 
    .responseJSON{(request, response, data, error) in 

     if (error == nil) 
     { 
      let json = JSON(data!) 
      token = json["TOKEN"].string! 
      println("jsonAPI = \(json) \n\n") 
      completion(token) 
     } 
     else 
     { 
      println("HTTP HTTP Request failed: \(error)") 
     } 

} 

Тогда вы называете:

api.TEST("letmein", {(newToken : String) in 
         token = newToken 
         println("\ntokenDidLOAD = \(token)\n") 
        }) 
0

Поскольку это println("jsonAPI = \(json) \n\n") в сторону блок операторов, который будет работать, как только просить получить полный, до этого компилятор будет работать следующие задания означают ваш println("\ntokenDidLOAD = \(token)\n"). Блок будет работать на другом субтрещине.

Если вы хотите распечатать println("\ntokenDidLOAD = \(token)\n"), когда запрос будет заполнен, тогда используйте блок на основе oncomplete.

Может, это поможет вам побить путь.

0

Alamofire извлекает данные асинхронно по умолчанию, что является желательным поведением почти для каждого сайта или приложения. К тому моменту, когда функция достигнет return token, запрос может быть еще не закончен.

Одна идея состоит в том, чтобы передать в затворе вашему API вызова будет выполняться после того, как запрос завершен:

func TEST(command: String, closure: (JSON) ->()) -> (String) { 

    var token:String = "" 

    // Form URL-Encoded Body 
    let bodyParameters = [ 
     "COMMAND":command, 
    ] 

    let encoding = Alamofire.ParameterEncoding.URL 

    // Fetch Request 
    Alamofire.request(.POST, "http://api.com/?v=1", parameters: bodyParameters, encoding: encoding) 
     .validate(statusCode: 200..<300) 
     .responseJSON{(request, response, data, error) in 

      if (error == nil) 
      { 
       let json = JSON(data!) 
       token = json["TOKEN"].string! 
       println("jsonAPI = \(json) \n\n") 
       closure(json) 
      } 
      else 
      { 
       println("HTTP HTTP Request failed: \(error)") 
      } 

     } 

    return token 

} 

Тогда вы могли бы назвать его с помощью:

api.TEST("letmein") { json in 
    let token = json["TOKEN"].stringValue 
    println("\ntokenDidLOAD = \(token)\n") 
} 

Замыкание принимает объект типа JSON как параметр, который вы можете использовать, чтобы делать все, что хотите, с помощью json внутри.

Также одно примечание: я предполагаю, что вы используете библиотеку SwiftyJSON. Раньше вы звонили json["TOKEN"].string!. Эта сила разворачивает необязательный вариант, которого следует избегать в целом (если вы не уверены, что он имеет значение). В таком случае вместо этого вы должны использовать json["TOKEN"].stringValue. Он возвращает String вместо String?

Смежные вопросы