Swift: handling an unexpected nil value, when variable is not optional [duplicate] - swift

This question already has answers here:
Check if property is set in Core Data?
(2 answers)
Closed 7 years ago.
I have a UITableViewController loading its entries from Core Data via a NSFetchedResultsController. Like this:
let historyItem = fetchedResults.objectAtIndexPath(indexPath) as HistoryItem
historyItem has a title property defined like this:
#NSManaged var title: String
So in cellForRowAtIndexPath the code says
cell?.textLabel?.text = historyItem.title
and that should all be fine. title is not an optional and does not need unwrapping.
However, in the past, the stored Core Data has acquired some objects where the value of the title property is nil. They are there stored, waiting to cause errors. If one of these objects is displayed in a cell, I will see a runtime address exception on the above Swift code line, where the address is 0.
For robustness, I need to write code to make sure the stored data delivered to my program does not cause crashes. However, I cannot write
if historyItem.title == nil { } // gives compiler error
because title is not an optional and the compiler will not let me. If I write
let optionalTitle:String? = historyItem.title
I still get a runtime EXC_BAD_ACCESS on that line.
How can I check that title is not erroneously nil?
Thanks!

Since you have nil values, the title property should be optional and you should declare it as optional in your core data model and in your NSManagedObject historyItem class.

When I do this in editor I dont get an error so might be the answer:
let a = ""
if a as String? == nil {
println("Nil")
}
else {
println("Not nil")
}

#NSManaged var title: String should be #NSManaged var title: String? if there is possibility for a nil value. Then, you cannot go wrong with optional binding:
if let historyItemTitle = historyItem.title {
cell?.textLabel?.text = historyItemTitle
} else {
cell?.textLabel?.text = "Title missing"
}

Related

I'm getting a constant 'error' used before being initialized message [duplicate]

This question already has an answer here:
Constant unassigned optional will not be nil by default
(1 answer)
Closed 6 years ago.
The following code works fine
struct carConfi {
var owner: String?
let brand: String = "BMW"
var currentMile: Double = 2000
}
let tomCar = carConfi()
However, if I change the type of the property owner to constant, there will be an error at the initializer
struct carConfi {
let owner: String? // Change to constant
let brand: String = "BMW"
var currentMile: Double = 2000
}
let tomCar = carConfi() //error: missing argument for parameter 'owner' in call
I did a bit search, it turns out that it is because the optional variables automatically have a default value of nil
I guess: Because once the constant is set, it then cannot be changed, if the optional constant automatically received an nil then it will keep as an unchangeable nil that's very silly and may against the users will
Question: My college doesn't fully convinced by the guess, he told me there must be more reasons for that. I would very appreciate if someone can explain that to me
Thx
Not setting a read-only (constant) field with either an:
initialization expression
initializer
is almost certainly an indication of an error in your program.
Since you have no other opportunity to set the value of your let field, the value of the field is going to remain nil (or some other default). It is rather unlikely that a programmer would find such behavior desirable, and request it on purpose.
That is why Swift marks this situation as an error. On the other hand, if you actually wanted your String constant to remain nil, you could add an expression to set it to nil, and silence the error:
let owner: String? = nil // Pretty useless, but allowed
Constants are set once, and once only. If you wanted it to be null or 0, then you would set it. You always define a constant on initiation.

multiple optional binding for a immutable variable and an immutable [duplicate]

This question already has an answer here:
Constant unassigned optional will not be nil by default
(1 answer)
Closed 6 years ago.
The following code works fine
struct carConfi {
var owner: String?
let brand: String = "BMW"
var currentMile: Double = 2000
}
let tomCar = carConfi()
However, if I change the type of the property owner to constant, there will be an error at the initializer
struct carConfi {
let owner: String? // Change to constant
let brand: String = "BMW"
var currentMile: Double = 2000
}
let tomCar = carConfi() //error: missing argument for parameter 'owner' in call
I did a bit search, it turns out that it is because the optional variables automatically have a default value of nil
I guess: Because once the constant is set, it then cannot be changed, if the optional constant automatically received an nil then it will keep as an unchangeable nil that's very silly and may against the users will
Question: My college doesn't fully convinced by the guess, he told me there must be more reasons for that. I would very appreciate if someone can explain that to me
Thx
Not setting a read-only (constant) field with either an:
initialization expression
initializer
is almost certainly an indication of an error in your program.
Since you have no other opportunity to set the value of your let field, the value of the field is going to remain nil (or some other default). It is rather unlikely that a programmer would find such behavior desirable, and request it on purpose.
That is why Swift marks this situation as an error. On the other hand, if you actually wanted your String constant to remain nil, you could add an expression to set it to nil, and silence the error:
let owner: String? = nil // Pretty useless, but allowed
Constants are set once, and once only. If you wanted it to be null or 0, then you would set it. You always define a constant on initiation.

Why optional constant does not automatically have a default value of nil [duplicate]

This question already has an answer here:
Constant unassigned optional will not be nil by default
(1 answer)
Closed 6 years ago.
The following code works fine
struct carConfi {
var owner: String?
let brand: String = "BMW"
var currentMile: Double = 2000
}
let tomCar = carConfi()
However, if I change the type of the property owner to constant, there will be an error at the initializer
struct carConfi {
let owner: String? // Change to constant
let brand: String = "BMW"
var currentMile: Double = 2000
}
let tomCar = carConfi() //error: missing argument for parameter 'owner' in call
I did a bit search, it turns out that it is because the optional variables automatically have a default value of nil
I guess: Because once the constant is set, it then cannot be changed, if the optional constant automatically received an nil then it will keep as an unchangeable nil that's very silly and may against the users will
Question: My college doesn't fully convinced by the guess, he told me there must be more reasons for that. I would very appreciate if someone can explain that to me
Thx
Not setting a read-only (constant) field with either an:
initialization expression
initializer
is almost certainly an indication of an error in your program.
Since you have no other opportunity to set the value of your let field, the value of the field is going to remain nil (or some other default). It is rather unlikely that a programmer would find such behavior desirable, and request it on purpose.
That is why Swift marks this situation as an error. On the other hand, if you actually wanted your String constant to remain nil, you could add an expression to set it to nil, and silence the error:
let owner: String? = nil // Pretty useless, but allowed
Constants are set once, and once only. If you wanted it to be null or 0, then you would set it. You always define a constant on initiation.

Swift: detecting an unexpected nil value in a non-optional at runtime: casting as optional fails

I have a UITableViewController loading its entries from Core Data via a NSFetchedResultsController. Like this:
let historyItem = fetchedResults.objectAtIndexPath(indexPath) as HistoryItem
historyItem has a title property defined like this:
#NSManaged var title: String
but somehow the core data has a nil value for title in some entries which causes EXC_BAD_ACCESS because title is not String?. This problem has been addressed at Check if property is set in Core Data? and the high-voted answer there suggests something like this:
if let possibleTitle = historyItem.title as String? {
NSLog("possibleTitle was set OK")
} else {
NSLog("possibleTitle was nil")
}
but I just tried that and it still gave me EXC_BAD_ACCESS:
That same problem and solution is also mentioned at
Swift - casting a nil core data string as an optional value and my earlier duplicate question Swift: handling an unexpected nil value, when variable is not optional
but it doesn't work for me. I'm using Xcode 6.2 and iOS8.
Am I misunderstanding something, please? Should this approach work?
I think you should make your title an optional if core data can return nil value for title
#NSManaged var title: String?
And test it without the cast
if let possibleTitle = historyItem.title{
NSLog("possibleTitle was set OK")
} else {
NSLog("possibleTitle was nil")
}

Printing optional variable

I am trying with these lines of code
class Student {
var name: String
var age: Int?
init(name: String) {
self.name = name
}
func description() -> String {
return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
}
}
var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())
Above code produces as follow
Daniel hides his age.
Daniel is Optional(18) years old.
My question is why there is Optional (18) there, how can I remove the optional and just printing
Daniel is 18 years old.
You have to understand what an Optional really is. Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.
Inside your description() function you don't print the Int, but instead you print the Optional. If you want to print the Int you have to unwrap the Optional. You can use "optional binding" to unwrap an Optional:
if let a = age {
// a is an Int
}
If you are sure that the Optional holds an object, you can use "forced unwrapping":
let a = age!
Or in your example, since you already have a test for nil in the description function, you can just change it to:
func description() -> String {
return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}
To remove it, there are three methods you could employ.
If you are absolutely sure of the type, you can use an exclamation mark to force unwrap it, like this:
// Here is an optional variable:
var age: Int?
// Here is how you would force unwrap it:
var unwrappedAge = age!
If you do force unwrap an optional and it is equal to nil, you may encounter this crash error:
This is not necessarily safe, so here's a method that might prevent crashing in case you are not certain of the type and value:
Methods 2 and three safeguard against this problem.
The Implicitly Unwrapped Optional
if let unwrappedAge = age {
// continue in here
}
Note that the unwrapped type is now Int, rather than Int?.
The guard statement
guard let unwrappedAge = age else {
// continue in here
}
From here, you can go ahead and use the unwrapped variable. Make sure only to force unwrap (with an !), if you are sure of the type of the variable.
Good luck with your project!
For testing/debugging purposes I often want to output optionals as strings without always having to test for nil values, so I created a custom operator.
I improved things even further after reading this answer in another question.
fileprivate protocol _Optional {
func unwrappedString() -> String
}
extension Optional: _Optional {
fileprivate func unwrappedString() -> String {
switch self {
case .some(let wrapped as _Optional): return wrapped.unwrappedString()
case .some(let wrapped): return String(describing: wrapped)
case .none: return String(describing: self)
}
}
}
postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
return x.unwrappedString
}
Obviously the operator (and its attributes) can be tweaked to your liking, or you could make it a function instead. Anyway, this enables you to write simple code like this:
var d: Double? = 12.34
print(d) // Optional(12.34)
print(d~?) // 12.34
d = nil
print(d~?) // nil
Integrating the other guy's protocol idea made it so this even works with nested optionals, which often occur when using optional chaining. For example:
let i: Int??? = 5
print(i) // Optional(Optional(Optional(5)))
print("i: \(i~?)") // i: 5
Update
Simply use me.age ?? "Unknown age!". It works in 3.0.2.
Old Answer
Without force unwrapping (no mach signal/crash if nil) another nice way of doing this would be:
(result["ip"] ?? "unavailable").description.
result["ip"] ?? "unavailable" should have work too, but it doesn't, not in 2.2 at least
Of course, replace "unavailable" with whatever suits you: "nil", "not found" etc
To unwrap optional use age! instead of age. Currently your are printing optional value that could be nil. Thats why it wrapped with Optional.
In swift Optional is something which can be nil in some cases. If you are 100% sure that a variable will have some value always and will not return nil the add ! with the variable to force unwrap it.
In other case if you are not much sure of value then add an if let block or guard to make sure that value exists otherwise it can result in a crash.
For if let block :
if let abc = any_variable {
// do anything you want with 'abc' variable no need to force unwrap now.
}
For guard statement :
guard is a conditional structure to return control if condition is not met.
I prefer to use guard over if let block in many situations as it allows us to return the function if a particular value does not exist.
Like when there is a function where a variable is integral to exist, we can check for it in guard statement and return of it does not exist.
i-e;
guard let abc = any_variable else { return }
We if variable exists the we can use 'abc' in the function outside guard scope.
age is optional type: Optional<Int> so if you compare it to nil it returns false every time if it has a value or if it hasn't. You need to unwrap the optional to get the value.
In your example you don't know is it contains any value so you can use this instead:
if let myAge = age {
// there is a value and it's currently undraped and is stored in a constant
}
else {
// no value
}
I did this to print the value of string (property) from another view controller.
ViewController.swift
var testString:NSString = "I am iOS Developer"
SecondViewController.swift
var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")
Result :
The Value of String is I am iOS Developer
Check out the guard statement:
for student in class {
guard let age = student.age else {
continue
}
// do something with age
}
When having a default value:
print("\(name) is \(age ?? 0) years old")
or when the name is optional:
print("\(name ?? "unknown") is \(age) years old")
I was getting the Optional("String") in my tableview cells.
The first answer is great. And helped me figure it out. Here is what I did, to help the rookies out there like me.
Since I am creating an array in my custom object, I know that it will always have items in the first position, so I can force unwrap it into another variable. Then use that variable to print, or in my case, set to the tableview cell text.
let description = workout.listOfStrings.first!
cell.textLabel?.text = description
Seems so simple now, but took me a while to figure out.
This is not the exact answer to this question, but one reason for this kind of issue.
In my case,
I was not able to remove Optional from a String with "if let" and "guard let".
So use AnyObject instead of Any to remove optional from a string in swift.
Please refer link for the answer.
https://stackoverflow.com/a/51356716/8334818
If you just want to get rid of strings like Optional(xxx) and instead get xxx or nil when you print some values somewhere (like logs), you can add the following extension to your code:
extension Optional {
var orNil: String {
if self == nil {
return "nil"
}
return "\(self!)"
}
}
Then the following code:
var x: Int?
print("x is \(x.orNil)")
x = 10
print("x is \(x.orNil)")
will give you:
x is nil
x is 10
PS. Property naming (orNil) is obviously not the best, but I can't come up with something more clear.
With the following code you can print it or print some default value. That's what XCode generally recommend I think
var someString: String?
print("Some string is \(someString ?? String("Some default"))")
If you are printing some optional which is not directly printable but has a 'to-printable' type method, such as UUID, you can do something like this:
print("value is: \(myOptionalUUID?.uuidString ?? "nil")")
eg
let uuid1 : UUID? = nil
let uuid2 : UUID? = UUID.init()
print("uuid1: \(uuid1?.uuidString ?? "nil")")
print("uuid2: \(uuid2?.uuidString ?? "nil")")
-->
uuid1: nil
uuid2: 0576137D-C6E6-4804-848E-7B4011B40C11