Swift: Check if variable is nil - xcode

I am currently learning Swift and I am experimenting with Core Data where I would like to save a linked list. To add an element at the end of the list I have a while-loop like this:
var curr = start
while (curr.nextElem != nil) {
curr = curr.nextElem
}
The problem is though that curr.next != nil seems to be invalid, following error is shown: 'ListElem' is not convertible to UInt8
I noticed this error a few times before but always found a way around comparing but how can this be done in this case?

Your ListElem.nextElem property seems to be returning an actual ListElem, so it can never be nil. For it to be able to be nil, it has to be of optional type (ListElem?).
Also, try the Xcode 6.3 beta — most of the error messages where Swift 1.1 said "I dunno what you're doing, so I'll just say you can't convert it to UInt8" have been replaced with better diagnostics in Swift 1.2.

Related

Swift optionals - warning on conditional cast from 'x' to 'x' always succeeds

I was wondering if there is a way to turn off/avoid 'yellow' warnings in xcode on if let...NSUserDefaults constructs where the key is of a known value.
For example:
if let x = NSUserDefaults.standardUserDefaults().integerForKey("myKey") as? Int {...}
Because of the if let I have to use as?. However, as I am using a known value type (in this case integer) the as? Int is effectively redundant - which is why I am getting the 'yellow warning'.
Thoughts? Is there a better way to code these types of constructs?
My suggestion would be to address the issue instead of silencing the warnings. :)
NSUserDefaults.standardUserDefaults().integerForKey("myKey") does not return an Optional, and the type is known, so you don't need neither optional binding with if let nor type casting with as?.
Just this:
let x = NSUserDefaults.standardUserDefaults().integerForKey("myKey")
will suffice, since .integerForKey just returns 0 if it can't get the actual value.
If you don't like this behavior of getting a default value (I don't), then don't use .integerForKey and use objectForKey with optional binding and type casting instead. Like you were doing first but with .objectForKey replacing .integerForKey. That way you'll get an actual nil if the value for the key is unreachable, not a default value.
if let x = NSUserDefaults.standardUserDefaults(). objectForKey("myKey") as? Int {...}
First of all check always the signature:
⌥-click on the symbol integerForKey: or look at Quick Help.
You will see:
func integerForKey(_ defaultName: String) -> Int
It reveals the return value is a non optional.
Non optionals can retrieved directly as described in Eric's answer without any type casting, optional binding causes an error.
That's one of the essential semantics in Swift.

How do you convert optional text input to Int in Swift 2, Xcode 7 beta using if let - toInt does not work

I'm having trouble converting optional input String to Int in order to do calculations on it.
let odoField = UITextField() // allows entry of text to iOS field
odoField.text = "12500" // simulated input
let odoString = odoField.text
// now here is where I get trouble...
if let odoInt = odoString.toInt() {
distance = Double(odoInt)
}
Apparently the toInt suffix is no longer part of Swift. I have tried the following:
if let odoInt = Int(odoString)() {
But then I get the error "Optional type String? is not unwrapped" and a suggestion to put a ! or ?, as in:
if let odoInt = Int(odoString!)() {
But then I STILL get the euro about unwrapping, with the suggestion that I add yet another !, then when I do that, another error that I get rid of the parens, like this:
if let odoInt = Int(odoString!)! {
And then I get ANOTHER error that "Initializer for conditional binding must have Optional type, not 'Int'."
I'm trying to create conditional unwrapping, here.
Help!
First thing to understand is that UITextField.text returns an optional string, so in your code, odoString is of type String?. Also, keep in mind that the Int constructor takes a String, not a String? so you have to unwrap the String? before you can use it. Just putting a ! after the variable (as in Int(odoString!)) will crash your app if the odoString is nil. Better would be something like this:
if let s = odoString, odoInt = Int(s) {
// odoInt is of type Int. It is guaranteed to have a value in this block
}
I've tested Daniel T's answer and it worked.
I have a situation where I want to get the result of a text field back as an optional Int. You can extend this to cover your case using the following code:
let odoInt = odoField.text != nil ? Int(odoField.text!) : nil
if let odoInt = odoInt {
// Use unwrapped odoInt here
}
Another option - for a more compact solution - is to use a flatMap:
let number = odoString.flatMap { Double($0) } ?? 0.0
In fact, it appears that the answer in Swift 2 (Xcode 7 beta 6) is simpler than anything above. The code does not choke on a nil value for odoString when I do e.g. the following:
if let odoInt = Int(odoString!) {
distance = Double(odoInt)
}
I therefore surmise, barring deeper knowledge to the contrary, that the compiler does treat this as "if the statement is True (the right side is valid), then define and initialize the variable, and continue with execution." I welcome further feedback. This does render unnecessary a lot of the extra code that is suggested above.

Swift 1.2 StringLiteralConvertable error

I recently updated to Xcode 6.3 with Swift 1.2, and received over 300 errors, most of which involved adding an exclamation point. One type of issue that will not go away, however, is the error that "'_' is not convertible to 'StringLiteralConvertable'". This appears multiple times, in these situations:
PFCloud.callFunctionInBackground("modifyUser", withParameters: ["objectId":user.objectId, "key":"won", "value":won as AnyObject],block:nil)
PFCloud.callFunctionInBackground("modifyUser", withParameters: ["objectId":friend.objectId, "key":"parties", "value":played], block:nil)
PFCloud.callFunctionInBackground("modifyUser", withParameters: ["objectId":creator.objectId, "key":"left", "value" :left], block: {
(error) in
self.remainingPotatos = PFUser.currentUser()["left"] as! Int
})
The error appears to be on the strings that are the keys of the dictionary, however, they are by definition StringLiteralConvertable. What gives?
UPDATE
This appears to be another case of Xcode detecting an error but not telling which one. After adding '!' after 'objectId', the error switched to being about the data type of the arguments. The error message is:
Cannot invoke 'callFunctionInBackground' with an argument list of type '(String, withParameters:NSDictionary, block(_)->(_)'
Which part is the problem? (Also, changing error to 'error:NSError?' gives a similar result.
UPDATE
Looking at the Parse documentation, the block signature should be
^(id result, NSError *error)
I tried changing the block to
{
(result, error) in
//code
}
But still receive the same error
Possibly not the only problem, but you appear to have a key in one of your dictionaries of "value"! which isn’t valid in 1.2 (and would have compiled, but not made much sense, in 1.1)
import Foundation
let left = "blah" as NSString
let dict = ["value"!:left]
results in error: '_' is not convertible to StringLiteralConvertible
This was a problem with Xcode detecting the wrong error at the wrong place. Adding an '!' after "currentUser()" fixed the problem, and the lines with nil blocks lost their errors with a clean.

PFQuery.getObjectWithId(objectId: String) --- 'AnyObject?' is not convertible to 'String' error --- Parse sdk 1.7.1 and Xcode 6.3

I just updated Xcode to 6.3 and my parse sdk to 1.7.1. I knew from the apple docs that I was going to spend some time fixing some of my swift code on my iOS app. Xcode is happy with all my fixes except for one func that gets a parse class by id. I've dredged parse, apple, stackoverflow, and google for a fix, but I've been banging my head against this last fix for hours and desperately need some help from one of you super smart guys. I apologize in advance if this turns out to be a stupid question. I've been programming for a really long time, but I'm a noob to iOS.
Below is a simple example of what I'm trying to do, which worked before I updated Xcode and parse sdk. Now Xcode gives me errors for each of the lines where I am trying to get the variables out from the PFObject. Errors for each line is like this: "'AnyObject?' is not convertible to 'String'" and "Cannot assign to immutable value of type 'String". Any insight would be greatly appreciated.
func getFakeObject(objectId: String) -> FakeObject {
var fakeObject: FakeObject = FakeObject()
var query = PFQuery(className:"FakeObject")
var loadedFakeObject = query.getObjectWithId(objectId)
if loadedFakeObject != nil {
fakeObject.objectId = objectId
fakeObject.isActive = loadedFakeObject["isActive"] as! Bool
fakeObject.desc = loadedFakeObject["desc"] as! String
fakeObject.purchasePrice = loadedFakeObject["purchasePrice"] as! Double
fakeObject.purchaseDate = loadedFakeObject["purchaseDate"] as! NSDate
fakeObject.labels = loadedFakeObject["labels"] as [String]
}
return fakeObject
}
Swift 1.2 is a lot stricter about syntax and tries to prevent you from unknowingly doing dangerous things.
Where you write:
var loadedFakeObject = query.getObjectWithId(objectId)
if loadedFakeObject != nil {
Try instead:
if let loadedFakeObject = query.getObjectWithId(objectId) {
In the first case, you are getting an optional (there might be no such object), and then checking it its nil, but then still using the optional. Because it’s optional, you need to write loadedFakeObject!["isActive"] as! Bool. But there’s really no need because instead you can use if let to both check and unwrap the optional, meaning within the if statement, it won’t be optional any more.
You might also want to consider switching to as? instead of as! in various places, but this is probably less the cause of your problem, more of a runtime safety thing.

Swift: masks as type properties

my problem. I'm working with a NSEvent, which happens to have a var modifierFlags of type NSEventModifierFlags.
I want to check whether the user had a modifier key pressed (Command), so basically I want to check if CommandKeyMask is on.
What's the best/right way to do this in Swift ?
The following works in Xcode7-beta3, Swift 2
In Swift 2, bit field style enums like NSEventModifierFlags have been updated to conform to the OptionSetType protocol.
If you want to check if an option set contains a specific option, you no longer need to use bitwise & and a nil check. You can simply ask the option set if it contains a specific value in the same way that you would check if an array contained a value.
if theEvent.modifierFlags.contains(.CommandKeyMask) {
Xcode6-Beta6 changed this again I believe, the following will now work:
if theEvent.modifierFlags & .CommandKeyMask != nil {
This is from an earlier Xcode 6 beta, the correct answer now (Xcode 7/Swift 2) is https://stackoverflow.com/a/32004398/669586
The following is possible:
if (theEvent.modifierFlags & NSEventModifierFlags.CommandKeyMask).value != 0 {
because there is a definition of & for RawOptionSet
func &<T : RawOptionSet>(a: T, b: T) -> T
However, note that RawOptionSet also implements LogicValue, so the following is possible, too:
if theEvent.modifierFlags & NSEventModifierFlags.CommandKeyMask {
Although I consider the first solution to be a bit more clear for the readers

Resources