Swift函数iOS中未返回数据[重复]

Posted

技术标签:

【中文标题】Swift函数iOS中未返回数据[重复]【英文标题】:Data not being returned in Swift function iOS [duplicate] 【发布时间】:2015-04-17 05:34:09 【问题描述】:

这可能是我对 Swift 的误解。我是这门语言的新手,而且我的背景是 Perl,这让我觉得 swift 的行为与众不同。

我有 2 个文件。 ViewController.swift 和 APICalls.swift。在视图控制器中,我有一个按钮功能。在这个函数中,我正在调用 APICalls 中的另一个函数。当我这样做时,APICalls 中的 println() 正在打印正确的数据,但是,它是在按钮函数中的 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 之前先打印。

【问题讨论】:

Difference between synchronous and asynchronous 您应该阅读 Alamofire 自述文件中的“响应处理”部分。它明确提到了异步过程。 类似问题的答案:***.com/questions/29377824/…、***.com/questions/29377824/…、***.com/questions/25141829/…(还有更多......) 【参考方案1】:

因为您发出的请求是异步的。您首先返回尚不存在的令牌,然后才真正完成请求。您不需要将令牌作为TEST 函数的返回值。你的 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")
                     )

【讨论】:

【参考方案2】:

因为这个println("jsonAPI = \(json) \n\n") 在块语句中,一旦请求完成就会运行,在此之前编译器将运行下一个作业意味着你的println("\ntokenDidLOAD = \(token)\n")。块将在另一个子线程上运行。

如果您想在请求完成时打印println("\ntokenDidLOAD = \(token)\n"),请使用基于oncomplete 的块。

希望这可以帮助您解决问题。

【讨论】:

【参考方案3】:

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类型的对象作为参数,你可以用它来做任何你想做的事情。

还有一件事需要注意:我假设您使用的是 SwiftyJSON 库。之前,你打电话给json["TOKEN"].string!。这个强制解包一个可选的,通常应该避免(除非你绝对确定它有一个值)。在这种情况下,您可能想改用json["TOKEN"].stringValue。它返回String 而不是String?

【讨论】:

以上是关于Swift函数iOS中未返回数据[重复]的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 中未加载 JSON 数据

异步数据返回中未定义的数据

在 iOS Swift 中使用 Delegated 和 Protocols 从 dataTaskWithRequest 返回数据

无法在 Swift 中的函数中返回值 [重复]

swift中有啥更好:一个函数返回一个变量或只是一个getter变量[重复]

Swift ios alamofire 数据在 viewDidLoad 中第一次返回空