Swift error while downcasting 'Any' - swift

The following code is almost exact replica from Apple Documentation and compiles without errors:
guard let firstItem = (rawItems! as? Array<Dictionary<String, Any>>)?.first else {
throw AnError()
}
let identityRef = firstItem[kSecImportItemIdentity as String]
as! SecIdentity? // !!!
guard let identity = identityRef else {
throw AnError()
}
The line marked with !!! contains forced downcast, while replacing as! with as quite obviously results in a compilation error 'Any?' is not convertible to 'SecIdentity?'... Indeed SecIdentity is a class while Any may not even be a class.
What I really cannot explain is the following. If I try to make the code safer, by using this
guard let idenity = firstItem[kSecImportItemIdentity as String] as? SecIdentity
else {
throw AnError()
}
or this
guard let idenityRef = firstItem[kSecImportItemIdentity as String] as? SecIdentity?
else {
throw AnError()
}
I get a compilation error: Conditional downcast to CoreFoundation type 'SecIdentity' will always succeed

SecIdentity is “an abstract Core Foundation-type object representing an identity, ” and the type of Core Foundation types can be
checked with CFGetTypeID(). So you can check the type ID first. If it matches the type ID of an
SecIdentity then the forced cast is safe:
guard let cfIdentity = firstItem[kSecImportItemIdentity as String] as CFTypeRef?,
CFGetTypeID(cfIdentity) == SecIdentityGetTypeID() else {
throw AnError()
}
let identity = cfIdentity as! SecIdentity
See also the bug report SR-7015 The CoreFoundation conditional downcast diagnostic is not as helpful as it should be:
The diagnostic should be updated with a message that informs the developer to compare CFTypeIds (with a fixit if possible).

CoreFoundation types behave a bit differently from Foundation types.
Don't conditional downcast the identity. If the optional binding succeeds you can force unwrap the identity
guard let idenity = firstItem[kSecImportItemIdentity as String] else { throw AnError() }
var privateKey : SecKey?
let status = SecIdentityCopyPrivateKey(identity as! SecIdentity, &privateKey)
Side note :
Please never write as? SecIdentity?.
Either it's conditional downcast as? SecIdentity or bridge cast an optional as SecIdentity?

Related

compare data in a firebase document using == gives Protocol 'Any' as a type cannot conform to 'Equatable'

so I want to be able to compare the data stored in a firestore document to determine if the user has done something before. But when I use the operator== on document data, it throws me Protocol 'Any' as a type cannot conform to 'Equatable'
func showInstructions() {
let user = Auth.auth().currentUser
let db = Firestore.firestore()
if user != nil {
if let email = user?.email{
let docRef = db.collection("\(email)").document("starting test(squats)")
docRef.getDocument { (document, error) in
if let document = document, document.exists, let data = document.data(){
if data == ["did starting test": 0] { <- Protocol 'Any' as a type cannot conform to 'Equatable'
}
} else {
print("Document does not exist")
}
}
}
}
As others have suggested, you need to specify the Type of data
the Any type is essentially telling the compiler that the variable could be anything, and the compiler is not smart enough to determine what it actually is by itself
The way around this is casting which is when you tell the compiler "this is a... (String, Int, Bool etc)"
in your case that would look like this
let data = document.data() as? [String: Int]
which is telling the compiler that data is a an array with a String key and Int values
note that if you use as? and the information you retrieved from Firestore is not what you expected, the cast will return nil instead. so you should check for that before using data

Swift 4 - Catch Error if Value not in Plist

I have this code
let path = self.userDesktopDirectory + "/Library/Preferences/.GlobalPreferences.plist"
let dictRoot = NSDictionary(contentsOfFile: path)
if let dict = dictRoot{
try print(dict["AppleLocale"] as! String)
}
If the Value "AppleLocale" didnt exists the script crashes. What I must add to "catch" the Error and avoid the crash?
If the Value "AppleLocale" didnt exists the script crashes. What I
must add to "catch" the Error and avoid the crash?
depends on what's the reason for causing the crash. Mentioning that "If the Value AppleLocale didnt exists" means the the reason for the crash would be the force casting:
dict["AppleLocale"] as! String
probably, it has nothing to do with the try, it would be:
Unexpectedly found nil while unwrapping an Optional value
Means that at some point dict["AppleLocale"] could be nil or even if it contains a value as not a string it will crash (optional). You have to make sure that dict["AppleLocale"] is a valid (not nil) string, there are more than just one approach to follow for doing it, for instance you could do optional binding, like this:
let path = self.userDesktopDirectory + "/Library/Preferences/.GlobalPreferences.plist"
let dictRoot = NSDictionary(contentsOfFile: path)
if let dict = dictRoot{
if let appleLocale = dict["AppleLocale"] as? String {
print(appleLocale)
} else {
// `dict["AppleLocale"]` is nil OR contains not string value
}
}
Actually, I would assume that you don't have to deal with try for such a case.

swift3 How to remove Optional [duplicate]

This question already has answers here:
Printing optional variable
(15 answers)
Cannot get rid of Optional() string
(5 answers)
Closed 5 years ago.
this is my code:
func uplouadPost() {
// shortcut to data to be php
let parseJSON = UserDefaults.standard.value(forKey: "parseJSON") as?
NSDictionary
let userID = parseJSON!["userID"] as! String
....
if error == nil {
do {
// json containes $returnArray from php
let json = try JSONSerialization.jsonObject(with: data!,
options: .mutableContainers) as? NSDictionary
print("========================\(userID)")
print I get ========================Optional(23)
But I don't want Optioanl
how to just get 23
What's more, I tried to unwrap the "userID" by this way. However it doesn't work
let unwrappedUserID = [userID]
print (unwrappedUserID)
Thank you guys
The best method of checking for and unwrapping Optionals is using either a guard statement or if-let statements.
So suppose you have a dictionary defined as:
let parseJson: [String: Any]? = ["userId": 23]
Even though it has a value, it is still an Optional type so to access the values in the dictionary we want, we need to check for the possibility of it having a nil value, assuming we didn't create it and know that it has a real value.
Using if-let statements, we can do:
if let json = parseJson {
// WILL ONLY EXECUTE IF parseJson IS NOT nil
// json is now of type [String: Any] instead of [String: Any]?
let userId = json["userId"]
print("=========\(userId)") // =========23
}
This creates a new scope where the json constant now contains the non-nil and unwrapped optional value of parseJson. In that case if parseJson did equal nil, then the code inside of the if-let block would not execute.
The other option is a guard statement, which is very similar.
guard let json = parseJson else {
// ONLY EXECUTES IF parseJson IS nil
// MUST EXIT CURRENT SCOPE AS A RESULT
return // or throw NSError()
}
let userId = json["userId"]
print("==========\(userId)") // ==========23
In this case, the code after the guard will only execute if parseJson is non-nil because the inside of the guard block must exit the scope.
Try this, let unwrappedUserID = userID!

Handling Swift Dicts: fatal error: can't unsafeBitCast between types of different sizes

I have a function in Swift that needs to be able to handle multiple types. Specifically, it needs to be able to parse both Dicts and Strings.
The problem I have is the Dicts could be several types, depending on their origin. So I could be provided with [String:Any] or [String:String] (coming from Swift) or [String:AnyObject] (coming from objc). The top level parsing function takes Any, which it then tests for specific types and attempts to parse them.
At first I just tried testing for if let dict = object as? [String:Any], but if I passed in another type [String:AnyObject] or [String:String] it failed. So I tried testing each type:
func parseLink(object: Any) {
if let dict = object as? [String:Any] {
return self.parseDict(dict)
} else if let dict = object as? [String:AnyObject] {
return self.parseDict(dict)
} else if let dict = object as? [String:String] {
return self.parseDict(dict)
} else if let string = object as? String {
return parseURL(string)
}
}
func parseDict(dict: [String:Any]) { ..... }
So I've created some Unit Tests to test the behavior:
func testDictTypes() {
let testDict: [String:Any] = [ "orgId" : "123456789" ]
let link = OrgContextLinkParser().parseLink(testDict)
XCTAssertNotNil(link)
let testDict1: [String:AnyObject] = [ "orgId" : "123456789" ]
let link2 = OrgContextLinkParser().parseLink(testDict1)
XCTAssertNotNil(link2)
let testDict3: [String:String] = [ "orgId" : "123456789" ]
let link3 = OrgContextLinkParser().parseLink(testDict3)
XCTAssertNotNil(link3)
}
This all compiles fine, but I get a fatal runtime error if a [String:AnyObject] is passed in. This is troubling since Swift's type system is supposed to prevent these kind of errors and I get no warning or errors thrown when I compile.
I also really don't want to duplicate the exact same logic multiple times just to handle different dict types. I.E., handling [String:Any], [String:AnyObject] and [String:String] have virtually the exact same logic.
The only possible solution I've seen is to actually duplicate the dictionary, which seems rather expensive (Convert [String: AnyObject] to [String: Any]). For performance reasons, it seems better to just copy paste the code and change the function signatures... but really!? That's seems excessive.
The best solution seems to be to parse a Dict as [String:AnyObject] and copy the value only if it's [String:Any]:
if let dict = object as? [String:Any] {
var objDict: [String:AnyObject] = [:]
for (key, value) in dict {
if let obj = value as? AnyObject {
objDict[key] = obj
}
}
return self.parseDict(objDict)
I don't particularly like this, but so far it's be best I've been able to come up with.
Does anyone have any idea how to handle this properly? I'm especially concerned that I can cast Any as [String:AnyObject], pass it to a function that takes [String:Any] and I get no compiler errors, even though it crashes at runtime.

Optional Types With Parse and Swift

if var findPublisher:PFQuery = PFUser.query(){
findPublisher.whereKey("objectId", equalTo:quote.objectForKey("publisher").objectId)//error here
}
I am getting an error Value of any optional type 'Any Object'? not unwrapped. I don't know what i have done incorrectly. I am a beginner so please bear with me:)
This is really a place where you would give each quote a pointer to a user object, and then you could just get the publisher of the quote without an extra query. But if you want to do it this way, you would do:
let query = PFUser.query()!
query.whereKey("objectId", equalTo: (quote["publisher"] as! String)) // You can unwrap it as long as you are sure that quote is not nil, and the publisher is set.
query.getFirstObjectInBackgroundWithBlock({ (user: PFObject?, error: NSError?) in
// check for errors and use the object
})
This way of doing it also creates Parse security issues, as anyone with your app's ID and key can get a full user list.
let findPublisher = PFUser.query()!
findPublisher.whereKey("objectId", equalTo: (quote["publisher"] as! String))
findPublisher.findObjectsInBackgroundWithBlock{
(objects:[AnyObject]?, error:NSError?)->Void in
if error == nil{
let user:PFUser = (objects as NSArray).lastObject as! PFUser//error here
cell.publisherLabel.text = user.username
}
}
I end up getting an error that says that AnyObject is not convertible to NSArray?