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?
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.
You have to do this (no optionals needed):
let returnValue = self.parseResponse(resultBody)
(self.status,self.message) = (returnValue.Status,returnValue.Error)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With