Swift 1.2 NSDate?! is not convertible to NSDate - swift

After upgrading to 1.2, I have the compile error:
NSDate?! is not convertible to NSDate
Code:
let dateCreated = photoCommentObjects[indexPath.row].createdAt as NSDate
Other attempt:
I also tried:
let dateCreated = photoCommentObjects[indexPath.row].createdAt as? NSDate
I get error:
Downcast from NSDate?! to 'NSDate' only unwraps optionals

This is a type problem. You have an array with AnyObject type and you cannot read a property on AnyObject.
//sample data
class PhotoComment {
let createdAt = NSDate()
}
let photoCommentObjects: [AnyObject] = [PhotoComment()]
//let's get the indexed object first and let's cast it from AnyObject
let photoComment = photoCommentObjects[indexPath.row] as! PhotoComment
//now trivially
let dateCreated = photoComment.createdAt
or
//let's cast the whole array first
let photoComments = photoCommentObjects as! [PhotoComment]
let dateCreated = photoComments[indexPath.row].createdAt

Have you tried?
let dateCreated = photoCommentObjects[indexPath.row].createdAt as! NSDate
Since Sift 1.2 you have to explicitly mark forced casting with !.
This as a reminder for you that if it fails, your app will crash.

Apparently photoCommentObjects[indexPath.row].createdAt is returning a type of NSDate?! which is an implicitly wrapped optional of an optional. To unwrap that, first cast the result to NSDate? with as to remove the implicitly wrapped optional, and then use optional binding to unwrap the resulting NSDate?:
if let dateCreated = photoCommentObjects[indexPath.row].createdAt as NSDate? {
// use dateCreated which is of type NSDate
}
The result is that dateCreated will be a plain NSDate.
Alternatively, you can use:
if let temp = photoCommentObjects[indexPath.row].createdAt, dateCreated = temp {
// each assignment unwraps one layer of Optional
// use dateCreated which is of type NSDate
} else {
println("something is nil")
}

Related

Why is this constant from a Dictionary not unwrapped?

I'm using some base swift functionality, the fact that you can unwrapped Optional values with a if. I am working on swift 4 and Xcode 10.3
let xyz: String? = nil
if let unwrappedValue = xyz {
print("This is unwrapped")
} else {
print("This is not unwrapped") // Program goes there
}
I have made a dictionary with an Optional value as an element, and when I try to unwrap it, it doesn't unwrap the variable, but keeps the Optional value.
var referenceDatesIdentifiers: [String: Date?] =
["ReferenceDateIdentifier": nil]
if let referenceDate = referenceDatesIdentifiers["ReferenceDateIdentifier"] {
referenceDateLabel.text = otherDateFormater.string(from: referenceDate!) // ReferenceDate is Optional and not unwrapped
}
Why isn't referenceDate unwrapped ?
I tried to export the elem of the Dictionary in a constant, but same problem, it's not unwrapped
let refDateOpt = referenceDatesIdentifiers["ReferenceDateIdentifier"]
if let referenceDate = refDateOpt {
referenceDateLabel.text = otherDateFormater.string(from: referenceDate!) // Reference date is also Optional and not unwrapped
}
What is happening ?
You should required again optionally unwrap date with type casting will fix your issue. Update code as follow:
if let referenceDate = referenceDatesIdentifiers["ReferenceDateIdentifier"] as? Date {
print(referenceDate)
}
The problem here is that it doesn't makes any sense to create a dictionary with a nil value. So instead of checking if the key exists before adding a value, I just add the value and check the value with a if let
In the end, this was the answer
var referenceDatesIdentifiers: [String : Date] = [:]
if let referenceDate = referenceDatesIdentifiers["ReferenceDateIdentifier"] {
referenceDateLabel.text = otherDateFormater.string(from: referenceDate)
}
You could use below way. It will work perfectly.Update code as follow:
var referenceDatesIdentifiers: [String: Date?] =
["ReferenceDateIdentifier": nil]
if let refDateOpt = referenceDatesIdentifiers["ReferenceDateIdentifier"] as? Date {
print(refDateOpt)
}
or
if let refDateOpt = referenceDatesIdentifiers["ReferenceDateIdentifier"]{
if let referenceDate = refDateOpt {
print(referenceDate)
}
}

Unwrapping long datatype in Swift Linux

I'm trying to get a record from MongoDB which has a DateTime property. This property is ISODate but is received as a long data type (milliseconds since 1970) through the Perfect-MongoDB API.
The code looks like this:
if var something = dictionary["Something"] as? [String:Any], var intDate = something["$date"] as? Int64
{
let date = Date(timeIntervalSince1970: TimeInterval(intDate/1000))
}
This code is working fine in Mac OSX. However in Linux, created["$date"] as? Int64 is always nil.
I've tried a couple of things, including using Double and NSNumber instead of Int64 but it is still nil.
Any ideas on how I can access this number? I need to convert it to a readable date, and the way I'm doing this is through TimeInterval() which needs a Double value for seconds after 1970, so it needs to be divisible by 1000 and convertible to Double during that step.
Edit: This is the NSNumber code where intDate is still nil and thus doesn't fall through the let date line. something is not nil
if var something = dictionary["Something"] as? [String:Any], var intDate = something["$date"] as? NSNumber
{
let date = Date(timeIntervalSince1970: TimeInterval(NSDecimalNumber(decimal:intDate.decimalValue/1000).doubleValue))
}
Edit 2: Sample Dictionary for this case:
var dictionary : [String:Any] = ["SomethingElse":"SomeOtherData","Something":["$date": 1507710414599]]
Apparently there is only limited conversion between integer types and NSNumber in Swift on Linux, so you have to cast to the exact type,
which is Int in this case:
let dictionary : [String: Any] = ["SomethingElse":"SomeOtherData","Something":["$date": 1507710414599]]
if let something = dictionary["Something"] as? [String:Any],
let numDate = something["$date"] as? Int {
let date = Date(timeIntervalSince1970: Double(numDate)/1000)
print("Date:", date)
}

Convert NSDate to Date

this might be a stupid question, but I can´t find the information. I'm using CoreData in my app, and I save an array of structs. The problem is when I fetch and try to restore it into the struct array, I have a problem with my Date variable; I can't find a way to convert it from NSDate to Date, I try using as Date, but it makes me force downcast and I'm not sure if it's safe. Is it correct? or is there another way?
This is my Struc:
struct MyData {
var value = Int()
var date = Date()
var take = Int()
var commnt = String()
}
This is how I'm fetchin the data:
func fetchRequestInfo() -> [MyData] {
let fetchRequest: NSFetchRequest<GlucoseEvents> = GlucoseEvents.fetchRequest()
do {
let searchResults = try DatabaseController.getContext().fetch(fetchRequest)
for result in searchResults as [GlucoseEvents] {
let value = Int(result.value)
let date = result.date as Date
let take = Int(result.take)
let commnt = String(describing: result.commnt)
let data = MyData(value: value, date: date, take: take, commnt: commnt)
self.dataArray.append(data)
}
} catch {
print ("error: \(error)")
}
let orderArray = self.dataArray.sorted(by: { $0.date.compare($1.date) == .orderedAscending})
return orderArray
}
And this is the how I set the properties of my CoreDataClass:
#NSManaged public var commnt: String?
#NSManaged public var date: NSDate?
#NSManaged public var value: Int16
#NSManaged public var take: Int16
result.date is an optional NSDate, so you can bridge it
to an optional Date:
result.date as Date?
Then use optional binding to safely unwrap it. In your case that
could be
guard let date = result.date as Date? else {
// date is nil, ignore this entry:
continue
}
You might also want to replace
let commnt = String(describing: result.commnt)
with
guard let commnt = result.commnt else {
// commnt is nil, ignore this entry:
continue
}
otherwise you'll get comment strings like Optional(My comment).
(Rule of thumb: String(describing: ...) is almost never what you
want, even if the compiler suggests it to make the code compile.)
Just make implicit casting like:
let nsdate = NSDate()
let date = nsdate as Date
You can use a function or just an extension:
let nsDate = NSDate()
let date = Date(timeIntervalSinceReferenceDate: nsDate.timeIntervalSinceReferenceDate)

Assign Value of NSNumber to AnyObject

I have a segment of code that gets info from an API, and I need to add it to a Dictionary. The code is below:
typealias JSONdic = [String: AnyObject]
var weatherData: AnyObject = StorageManager.getValue(StorageManager.StorageKeys.WeatherData)!
let json: AnyObject = ["Any": "Object"]
if let json = json as? JSONdic, history = json["history"] as? JSONdic, tempi = history["tempi"] as? Int, hum = history["hum"] as? String, precip = history["precipi"] as? String{
println("Temperature:\(tempi) Humidity:\(hum) Precipitation:\(precip)")
weatherData = [NSDate: AnyObject]()
let temp = tempi as NSNumber
weatherData[(The Current Date)] = temp
}
I want to first add "temp" to the weatherData Dictionary, but even after casting it to NSNumber, I am told that an NSNumber value cannot be assigned to the AnyObject?! type. Can anyone help me fix this?
Your weatherData variable is of type AnyObject. Despite the fact that you later assign it a value of type [NSDate: AnyObject], the variable itself is still considered by the compiler to be AnyObject. You then hit problems because you try to subscript it, assigning an NSNumber, which is obviously not possible on AnyObject.
Your declaration of weatherData should ensure it is the type you intend. If you are sure that your StorageManager will return you the appropriate dictionary type for the weather data key, you can force downcast it to the correct type:
var weatherData = StorageManager.getValue(StorageManager.StorageKeys.WeatherData) as! [NSDate: NSObject]

Downcasting optionals in Swift: as? Type, or as! Type?

Given the following in Swift:
var optionalString: String?
let dict = NSDictionary()
What is the practical difference between the following two statements:
optionalString = dict.objectForKey("SomeKey") as? String
vs
optionalString = dict.objectForKey("SomeKey") as! String?
The practical difference is this:
var optionalString = dict["SomeKey"] as? String
optionalString will be a variable of type String?. If the underlying type is something other than a String this will harmlessly just assign nil to the optional.
var optionalString = dict["SomeKey"] as! String?
This says, I know this thing is a String?. This too will result in optionalString being of type String?, but it will crash if the underlying type is something else.
The first style is then used with if let to safely unwrap the optional:
if let string = dict["SomeKey"] as? String {
// If I get here, I know that "SomeKey" is a valid key in the dictionary, I correctly
// identified the type as String, and the value is now unwrapped and ready to use. In
// this case "string" has the type "String".
print(string)
}
as? Types - means the down casting process is optional. The process can be successful or not(system will return nil if down casting fails).Any way will not crash if down casting fails.
as! Type? - Here the process of down casting should be successful (! indicates that) . The ending question mark indicates whether final result can be nil or not.
More info regarding "!" and "?"
Let us take 2 cases
Consider:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
Here we don't know whether the result of down casting of cell with identifier "Cell" to UITableViewCell is success or not. If unsuccessful then it returns nil( so we avoid crash here). Here we can do as given below.
if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell {
// If we reached here it means the down casting was successful
}
else {
// unsuccessful down casting
}
So let us remember it like this - If ? it means we are not sure whether value is nil or not (question mark comes when we don't know things).
Contrast that to:
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell.
Here we tell the compiler that down casting should be successful. If it fails the system will crash. So we give ! when we are sure that value is non nil.
To clarify what vacawama said, here is an example...
Swift 3.0:
import UIKit
let str_value: Any = String("abc")!
let strOpt_value: Any? = String("abc")!
let strOpt_nil: Any? = (nil as String?)
let int_value: Any = Int(1)
let intOpt_value: Any? = Int(1)
let intOpt_nil: Any? = (nil as Int?)
// as String
//str_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//int_value as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_value as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_nil as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
// as? String
str_value as? String // == "abc"
strOpt_value as? String // == "abc"
strOpt_nil as? String // == nil
int_value as? String // == nil
intOpt_value as? String // == nil
intOpt_nil as? String // == nil
// as! String
str_value as! String // == "abc"
strOpt_value as! String // == "abc"
//strOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.
//int_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_value as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_nil as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.
// as String?
//str_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//strOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//strOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//int_value as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//intOpt_value as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//intOpt_nil as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
// as? String?
//str_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
strOpt_value as? String? // == "abc"
strOpt_nil as? String? // == nil
//int_value as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
intOpt_value as? String? // == nil
intOpt_nil as? String? // == nil
// as! String?
//str_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
strOpt_value as! String? // == "abc"
strOpt_nil as! String? // == nil
//int_value as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//intOpt_value as! String? // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
intOpt_nil as! String? // == nil
// let _ = ... as String
//if let _ = str_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = int_value as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
// let _ = ... as? String
if let _ = str_value as? String { true } // true
if let _ = strOpt_value as? String { true } // true
if let _ = strOpt_nil as? String { true } // false
if let _ = int_value as? String { true } // false
if let _ = intOpt_value as? String { true } // false
if let _ = intOpt_nil as? String { true } // false
// let _ = ... as! String
//if let _ = str_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = int_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_nil as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
// let _ = ... as String?
//if let _ = str_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = strOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = int_value as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = intOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
// let _ = ... as? String?
//if let _ = str_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = strOpt_value as? String? { true } // true
if let _ = strOpt_nil as? String? { true } // true
//if let _ = int_value as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = intOpt_value as? String? { true } // false
if let _ = intOpt_nil as? String? { true } // true
// let _ = ... as! String?
//if let _ = str_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
if let _ = strOpt_value as! String? { true } // true
if let _ = strOpt_nil as! String? { true } // false
//if let _ = int_value as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//if let _ = intOpt_value as! String? { true } // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
if let _ = intOpt_nil as! String? { true } // false
Swift 2.0:
import UIKit
let str: AnyObject = String("abc")
let strOpt: AnyObject? = String("abc")
let strNil: AnyObject? = (nil as String?)
let int: AnyObject = Int(1)
let intOpt: AnyObject? = Int(1)
let intNil: AnyObject? = (nil as Int?)
str as? String // == "abc"
strOpt as? String // == "abc"
strNil as? String // == nil
int as? String // == nil
intOpt as? String // == nil
intNil as? String // == nil
str as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
strOpt as! String? // == "abc"
strNil as! String? // == nil
int as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
intOpt as! String? // Run-Time Error: Could not cast value of type '__NSCFNumber' to 'NSString'
intNil as! String? // == nil
as used for upcasting and type casting to bridged type
as? used for safe casting, return nil if failed
as! used to force casting, crash if failed
Note:
as! can’t cast raw type to optional
Examples:
let rawString: AnyObject = "I love swift"
let optionalString: AnyObject? = "we love swift"
let nilString: AnyObject? = (nil as String?)
let rawInt: AnyObject = Int(3)
let optionalInt: AnyObject? = Int(3)
let nilInt: AnyObject? = (nil as Int?)
Example
var age: Int? = nil
var height: Int? = 180
By adding a ? immediately after the data type you tell the compiler that the variable might contain a number or not. Neat! Notice that it doesn’t really make sense to define Optional constants – you can set their value only once and therefore you would be able to say whether their value will be nil or not.
When we should use "?" and when "!"
let’s say we have UIKit based simple app.
we have some code in our view controller and wants to present a new view controller on top of it.
and we need to decide to push the new view on screen using navigation controller.
As we know every ViewController instance has a property navigation controller.
If you are building a navigation controller based app this property of your app’s master view controller is set automatically and you can use it to push or pop view controllers. If you use a single app project template – there won’t be a navigation controller created automatically for you, so your app’s default view controller will not have anything stored in the navigationController property.
I’m sure you already guessed that this is exactly a case for an Optional datatype. If you check UIViewController you will see that the property is defined as:
var navigationController: UINavigationController? { get }
So let’s go back to our use case. If you know for a fact that your view controller will always have a navigation controller you can go ahead and force unwrap it:
controller.navigationController!.pushViewController(myViewController, animated: true)
When you put a ! behind the property name you tell the compiler I don’t care that this property is optional, I know that when this code executes there always will be a value store so treat this Optional like a normal datatype. Well isn’t that nice? What would happen though if there isn’t a navigation controller to your view controller? If you suggestion that there always will be a value stored in navigationController was wrong? Your app will crash. Simple and ugly as that.
So, use ! only if you are 101% sure that this is safe.
How about if you aren’t sure that there always will be a navigation controller? Then you can use ? instead of a !:
controller.navigationController?.pushViewController(myViewController, animated: true)
What the ? behind the property name tells the compiler is I don’t know whether this property contains nil or a value, so: if it has value use it, and oterwise just consider the whole expression nil. Effectively the ? allows you to use that property just in the case there is a navigation controller. No if checks of any kind or castings of any sort. This syntax is perfect when you don’t care whether you have a navigation controller or not, and want to do something only if there is.
Huge thanks to Fantageek
They are two different forms of Downcasting in Swift.
(as?), which is know to be the Conditional Form, returns an optional value of the type you are trying to downcast to.
You can use it when you are not sure if the downcast will succeed.
This form of the operator will always return an optional value, and
the value will be nil if the downcast was not possible. This enables
you to check for a successful downcast.
(as!), which is know to be the Forced Form, attempts the downcast and force-unwraps the result as a single compound action.
You should use it ONLY when you are sure that the downcast will
always succeed. This form of the operator will trigger a runtime
error if you try to downcast to an incorrect class type.
For more details, please check Type Casting section of Apple's documentation.
Maybe this code example will help someone grok the principle:
var dict = [Int:Any]()
dict[1] = 15
let x = dict[1] as? String
print(x) // nil because dict[1] is an Int
dict[2] = "Yo"
let z = dict[2] as! String?
print(z) // optional("Yo")
let zz = dict[1] as! String // crashes because a forced downcast fails
let m = dict[3] as! String?
print(m) // nil. the forced downcast succeeds, but dict[3] has no value
The first is a "conditional cast" (look under "type-casting operators" in the documentation I've linked). If the cast succeeds, the value of the expression is wrapped in an optional and returned, otherwise the value returned is nil.
The second means that optionalString could be a string object or it might be nil.
More information found in this related question.
It may be easiest to remember the pattern for these operators in Swift as: ! implies "this might trap," while ? indicates "this might be nil."
refer to:
https://developer.apple.com/swift/blog/?id=23
I am novice to Swift and writing this example trying to explain as i understand about 'optionals'. If i am wrong please correct me.
Thanks.
class Optional {
var lName:AnyObject! = "1"
var lastName:String!
}
let obj = Optional()
print(obj.lName)
print(obj.lName!)
obj.lastName = obj.lName as? String
print(obj.lastName)
(1) : obj.lastName = obj.lName as! String
vs
(2) : obj.lastName = obj.lName as? String
Ans : (1) Here programmer is damm sure that “obj.lName” contains string type object. So just give that value to “obj.lastName”.
Now, if programmer is correct means "obj.lName" is string type object, then no problem. "obj.lastName" will set to the same value.
But if programmer is wrong means "obj.lName" is not string type object i.e. it contains some other type object like "NSNumber" etc. Then CRASH (Run Time Error).
(2) Programmer is not sure that “obj.lName” contains string type object or any other type object. So set that value to “obj.lastName” if it is string type.
Now, if programmer is correct means “obj.lName” is string type object, then no problem. “obj.lastName” will set to the same value.
But if programmer is wrong means obj.lName is not string type object i.e. it contains some other type object like "NSNumber" etc. Then “obj.lastName” will set to the nil value. So, No Crash (Happy:)