Swift tuple to Optional assignment

老子叫甜甜 提交于 2019-12-06 18:28:13

问题


I am writing some code in Swift to learn the language. Here is my base class:

import Foundation
class BaseCommand:NSOperation
{
    var status:Int? = nil
    var message:String? = nil

    func buildRequest() -> NSData?
    {
        return nil
    }

    func parseResponse(data:NSData?) -> (Status:Int, Error:String)
    {
        return (200, "Success")
    }

    override func main() {
        let requestBody = self.buildRequest()

        println("Sending body \(requestBody)")
        // do network op
        var networkResultBody = "test"

        var resultBody:NSData = networkResultBody.dataUsingEncoding(NSUTF8StringEncoding)!
        (self.status, self.message) = self.parseResponse(resultBody)
    }
}

The problem is on the last line:

(self.status, self.message) = self.parseResponse(resultBody)

The compiler says "Cannot express tuple conversion (Status:Int, Error:String) to (Int?, String?)"

I understand that the issue is that self.status and self.message are optionals, and the parseResponse does not return Optionals (and I don't want it to). How do I tell it to do the necessary assign and convert to get the data into the instance variables?


回答1:


Another answer suggested (before it was changed) to just do:

(self.status!, self.message!) = self.parseResponse(resultBody)

I have found that is unsafe. It will crash if either self.status or self.message is nil at the time of the assignment. Try this test in a Playground:

class Test {
    var status: Int?
    var error: String?

    func parseResponse() -> (Status:Int, Error:String)
    {
        return (200, "Success")
    }

    func testIt() {
        (self.status!, self.error!) = parseResponse()
        print(self.status)
        print(self.error)
    }
}

let mytest = Test()
mytest.testIt()

Here is another way it could be done:

let (stat, err) = self.parseResponse(resultBody)
(self.status, self.error) = (Optional(stat), Optional(err))

or, as @AndriyGordiychuk discovered, it works without Optional:

let (stat, err) = self.parseResponse(resultBody)
(self.status, self.error) = (stat, err)

It's curious that that works, but assigning the result of the function does not.


Note the following experiment:

var i: Int?
var s: String?

// This works
(i, s) = (3, "hello")

// This fails with error: cannot express tuple conversion '(Int, String)' to '(Int?, String?)
let t = (3, "hello")
(i, s) = t

It seems that when the assignment is a tuple literal assigned to a tuple, Swift takes a shortcut and doesn't first construct the tuple. Instead, is just assigns the individual elements.

So this:

(i, s) = (3, "hello")

is equivalent to:

i = 3
s = "hello"

which works because you can assign an Int to an Int? variable and a String to a String? variable. The tuple assignment fails because the types need to match.




回答2:


You have to do this (no optionals needed):

let returnValue = self.parseResponse(resultBody)
(self.status,self.message) = (returnValue.Status,returnValue.Error)


来源:https://stackoverflow.com/questions/32173623/swift-tuple-to-optional-assignment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!