I make POST request to the server from my app, and I get jsonString as the response. I have made function to convert string to dictionary which looks like this:
func convertStringToDictionary(text: String) -> [String:AnyObject]? {
if let data = text.dataUsingEncoding(NSUTF8StringEncoding) {
do {
return try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String:AnyObject]
} catch let error as NSError {
print(error)
}
}
return nil
}
after getting the response from the server I convert the string to dictionary by function and then I want to check if user is logged in:
let result = convertStringToDictionary(jsonString as String)
if (result!["loggedIn"] == "1")
{
print("You are logged in!")
}
And then I get the error "Cannot convert value of type AnyObject? to expected argument String". I suppose I have to convert variable of type AnyObject to String if i want to compare it to string. I have tried every option which I have found on the Google but I havent got it to work.
Because result is a dictionary of type [String : AnyObject], the values you extract from it will be typed as AnyObject?, which has no valid operator overload for == with a String. You need to cast the extracted value to a String before you can compare it to "1".
What you probably want is something like:
if let result = convertStringToDictionary(jsonString as String),
loggedIn = result["loggedIn"] as? String
where loggedIn == "1" {
print("You are logged in")
}
Note that if your JSON has the "loggedIn" field as an Integer, like:
{
"loggedIn" : 1
}
You would want to cast loggedIn as Integer, not String.
You have to tell the compiler that the expected type is a String
if let loggedIn = result?["loggedIn"] as? String where loggedIn == "1" { ...
Related
I am new to Swift and have a requirement to store a database of key value pairs. The key value pairs are a name with a corresponding 4 digit number in database that remains in memory after the app is excited. I am thinking to use a dictionary with the name as the key and the 4 digit numbers as the value. These are then stored in the iPad flash memory using the user defaults class.
Below is the code that I’ve currently developed. The code that adds to the database compiles ok but the code that checks the name and number for a match in the database won't compile due to the following message (Value of optional type '[Any]?' not unwrapped; did you mean to use '!' or '?'?) which is because of this line of code (if let databaseCheck = database[name]). Ive obviously tried unwrapping but can't seem to shake the error message.
Anyone got any ideas whats causing the error or any issues with the approach?
public func checkDatabaseMatch( _ name: String, _ number: String) -> Bool
{
var foundInDatabaseFlag: Bool = false
let database = UserDefaults.standard.array(forKey: "Database")
if let databaseCheck = database[name]
{
if (databaseCheck == number)
{
foundInDatabaseFlag = true
}
}
return foundInDatabaseFlag
}
public func saveToDatabase( _ name: String, _ number: String)
{
var newEntry: [String: String] = [:]
newEntry[name] = number
UserDefaults.standard.set(newEntry, forKey: "Database")
}
There is a major mistake. You save a dictionary but retrieve an array.
Apart from that a dictionary retrieved from UserDefaults is [String:Any] by default, you have to conditional downcast the object.
The code checks if there is a dictionary in UserDefaults and if there is the requested key in one expression
public func checkDatabaseMatch( _ name: String, _ number: String) -> Bool
{
guard let database = UserDefaults.standard.dictionary(forKey: "Database") as? [String:String],
let databaseCheck = database[name] else { return false }
return databaseCheck == number
}
Another mistake is that you are always overwriting the entire dictionary in UserDefaults. If you want to save multiple key-value pairs you have to read the dictionary first.
public func saveToDatabase( _ name: String, _ number: String)
{
var newEntry : [String: String]
if let database = UserDefaults.standard.dictionary(forKey: "Database") as? [String:String] {
newEntry = database
} else {
newEntry = [:]
}
newEntry[name] = number
UserDefaults.standard.set(newEntry, forKey: "Database")
}
Side note: The parameter labels are highly recommended in Swift for better readability.
I have a project built in Swift 1.5. When I converted the code to swift 3.0 it started showing me errors in each 'if' statement in below code:
convenience init?(userInfo: [NSObject: AnyObject]) {
guard let statusString = userInfo[ConnectionMessage.StatusKey] as? String else {
return nil
}
guard let status = ConnectionStatus(string: statusString) else {
return nil
}
guard let connectionId = userInfo[ConnectionMessage.ConnectionIdKey]?.longLongValue else {
return nil
}
var ssid = ""
if let newSsid = userInfo[ConnectionMessage.SSIDKey] as? String {
ssid = newSsid
}
var password = ""
if let pw = userInfo[ConnectionMessage.PasswordKey] as? String {
password = pw
}
let buyerName = userInfo[ConnectionMessage.BuyerNameKey] as? String
self.init(status: status, connectionId: connectionId, ssid: ssid, password: password, buyerName: buyerName)
}
The error is
Ambiguous reference to member subscript
I tried the solutions found on StackOverflow but no luck. Please guide.
Change userInfo from [NSObject : AnyObject] to [String : AnyObject]. This assumes all of your ConnectionMessage.xxxKey values are String.
You also need to ensure that the dictionary you pass into the userInfo parameter is actually a dictionary with keys of type String.
I want to get a record from my parse.com class called "Tags" by ID. I want to retrieve data from the object "username" and "tagtext". Afterwords I want to save "username" to the String "username" and "tagtext" to the String "tagtext". My code looks like this, but I'm getting an error called 'AnyObject?' is not convertible to 'String' in the commented section:
var query = PFQuery(className:"Tags")
query.getObjectInBackgroundWithId("IsRTwW1dHY") {
(gameScore: PFObject?, error: NSError?) -> Void in
if error == nil && gameScore != nil {
let username = gameScore["username"] as! String // Error here
let tagtext = gameScore["tagtext"] as! String // Error here
} else {
println(error)
}
}
In Swift String is not an object. You need to cast NSString instead of String. Once you do you can then assign your NSString to a variable of type String.
edit following comment
You can do something like this:
if let username = gameScore["username"] as? NSString {
// If we get here, we know "username" exists, and we know that we
// got the type right.
self.username = username
}
I'm trying the value of an access token in Swift. I'm loading the token using Locksmith like so:
let (dictionary, error) = Locksmith.loadDataForUserAccount("userAccount")
This returns the following in the console:
Optional({
"access_token" = 123123123123123;
})
I'm using SwiftyJSON to extract the value of the access token
var access_token = dictionary["access_token"].stringValue
I'm getting the following error:
'NSDictionary?' does not have a member named 'subscript'
Any idea why?
LockSmith returns (NSDictionary?, NSError?):
public class func loadDataForUserAccount(userAccount: String, inService service: String = LocksmithDefaultService) -> (NSDictionary?, NSError?)
So, in your case dictionary itself is Optional:
Try:
var access_token = dictionary?["access_token"] as? String
Here, access_token is String?, it can be nil. If you want to store it to AnyObject variable, you must unwrap it. For example, using "Optional Binding":
if let token = access_token {
// Here, `token` is `String`, while `access_token` is `String?`
self.access_token = token
}
Or more directly:
if let access_token = dictionary?["access_token"] as? String {
// Here, access_token is `String`, not `String?`
self.access_token = token
}
else {
// error handling...
}
BTW, If you want to use SwiftyJSON, you should create JSON object from dictionary.
if let dict = dictionary {
var json = JSON(dict)
var access_token = json["access_token"].stringValue
}
As described at your 'NSDictionary?' Dictionary is an optional. You have to unwrap your optional before extracting stringValue from it. You can safely unwrap it using if let:
Edit
taking a hint from Rintaro as mentioned by him LockSmith returns an optional Dictionary so you need to first unwrap your dictionary and them you can unwrap access_token key value
if let dictionary = dictionary {
if let access_token = dictionary["access_token"] as? Int { // or as? String
println(access_token)
} else {
println(false)
}
} else {
println(false)
}
or if it returns a [String:String] Dictionary there is no need to cast the value to String
if let dictionary = dictionary {
if let access_token = dictionary["access_token"] {
println(access_token)
} else {
println(false)
}
} else {
println(false)
}
I'm making an extension on Dictionary, just a convenience method to traverse a deep json structure to find a given dictionary that might be present. In the general extension of a Dictionary, i'm not able to subscript because i give a String instead of a Key
extension Dictionary {
func openingHoursDictionary() -> Dictionary<String,AnyObject>? {
if let openingHours = self["openingHours"] as? Array<AnyObject> {
// traverses further and finds opening hours dictionary
}
return nil
}
}
Error: String is not convertible to DictionaryIndex<Key, Value>
on self["openingHours"]
How can i make a Key from the String "openingHours" or check the dictionary for ths string?
You can check at runtime if the string is a valid key for the dictionary:
extension Dictionary {
func openingHoursDictionary() -> [String : AnyObject]? {
if let key = "openingHours" as? Key {
if let openingHours = self[key] as? Array<AnyObject> {
// traverses further and finds opening hours dictionary
}
}
return nil
}
}
But this will "silently" return nil if called for other dictionaries
like [Int, AnyObject].
If you want the compiler to check if it is safe to subscript the
dictionary with a string then you have to use a (generic) function:
func openingHoursDictionary<T>(dict : [String : T]) -> [String : AnyObject]? {
if let openingHours = dict["openingHours"] as? Array<AnyObject> {
// traverses further and finds opening hours dictionary
}
return nil
}
It is (currently) not possible to write Dictionary (or Array)
extension methods that apply only to a restricted type of the
generic parameters.
Just cast the String as Key using "openingHours" as Key
if let pickupPoints = self["openingHours" as Key] as? Array<AnyObject> {
}
Downside is that if doing this i will get a crash if i have a Dictionary<Int,AnyObject> and use the method there.
0x10e8c037d: leaq 0x362aa(%rip), %rax ; "Swift dynamic cast failure"