func resetUserDefaults() {
let userDefaults = UserDefaults.standard
let dict = userDefaults.dictionaryRepresentation()
for (key,_) in dict {
if let key = key as? String {
userDefaults.removeObject(forKey: key)
} else {
#if DEBUG
NSLog("\(key)")
#endif
}
}
}
I'm getting this warning. can anyone suggest me how to avoid this warnoing
All keys in UserDefaults must be of type String. So key is declared as a String. So attempting to cast it to a String is pointless. Hence the warning.
All you need is:
func resetUserDefaults() {
let userDefaults = UserDefaults.standard
let dict = userDefaults.dictionaryRepresentation()
for (key,_) in dict {
userDefaults.removeObject(forKey: key)
}
}
There is no need to cast something to the type that it is already known (to the compiler) to have.
Just remove the whole condition and use your key directly.
Since the keys in the UserDefault should of type String, casting the key to string is of no use, and hence you are getting this warning.
func resetUserDefaults() {
let userDefaults = UserDefaults.standard
let dict = userDefaults.dictionaryRepresentation()
for (key, _) in dict {
userDefaults.removeObject(forKey: key)
}
}
It will always show waring because dictionaryRepresentation() return [String : Any].
So when you cast from string to string it will definitely show warning.
for more see this -> https://developer.apple.com/documentation/foundation/userdefaults/1415919-dictionaryrepresentation
I had the same issue with a private function in Swift 5 and I found a solution working for me.
The solution was to change the value to optional.
I added a question mark after the type I was looking for. (as String"?")
You can see an example here :
private func doSomeThing(completion: #escaping (String) -> ()) {
let Something = somethingElse;
if let anoterThing = something as String?{
completion(anoterThing)
}else{
completion("Error at private func doSomeThing")
}
}
You can find more pieces of information here:
https://docs.swift.org/swift-book/LanguageGuide/OptionalChaining.html
Swift: difference as String? vs. as? String
Downcasting in Swift with as and as?
Best Regards
Related
import Foundation
enum Errors: Error {
case badParse
}
public typealias JSONDictionary = [String: Any]
public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL {
guard let string = dictionary[key] as? String else {
throw Errors.badParse
}
if let url = URL(string: string) {
return url
}
throw Errors.badParse
}
public func decode<T>(_ dictionary: JSONDictionary, key: String) throws -> T {
guard let value = dictionary[key] else {
throw Errors.badParse
}
guard let attribute = value as? T else {
throw Errors.badParse
}
return attribute
}
let url: URL = try decode(["url":"test/url"], key: "url") // url: test/url
let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") // nil
The above code works as long as you're decoding a NON-optional. The specific non-generic decode function is called and the URL is constructed.
However, if you have an optionally type variable and decode it, it will not use the correct function. In swift 4.2, both optionals and non optionals would use the correct non-generic function, but since I updated to Xcode 11 swift 5.1, this behavior has been seen.
Any help would be greatly appreciated!
I would prefer not to make function signatures with optional returns such as
public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL? {
because it is not scalable...and it used to work without it.
Evidently, how type inference works changed a little bit in Swift 5. If you just want it to use the correct overload, you just need to give it a little push:
let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") as URL
by adding as URL at the end.
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've been away for a while from swift development. And today I got bug report from my client on my old project. The thing is I used to access value from my dictionary with ease just like dictionary[key] then I already got the value, but today I got below error by doing that:
Type 'NSFastEnumerationIterator.Element' (aka 'Any') has no subscript members
and here is my code:
var rollStatusArray = NSMutableArray()
for statusDict in rollStatusArray{
if statusId == "\(statusDict["mark_status_id"]!!)"{
return "\(statusDict["mark_status_name"]!!)"
}
}
How can I access dictionary value on swift 3?
In Swift's use native type Array/[] instead of NS(Mutable)Array.
if let dicArray = rollStatusArray.objectEnumerator().allObjects as? [[String:Any]] {
for statusDict in dicArray {
//Here compiler know type of statusDict is [String:Any]
if let status_id = statusDict["mark_status_id"] as? String, status_id == statusId {
return "\(statusDict["mark_status_name"]!)"
}
}
}
Note I'm force wrapping the mark_status_name value you can use Nil coalescing operator to return empty string to remove force wrapping.
You need to tell compiler the type of your statusDict this way:
for statusDict in rollStatusArray {
if let obj = statusDict as? [String: AnyObject] {
let statusIdFromDict = obj["mark_status_id"] as? String ?? ""
if statusId == statusIdFromDict {
return statusIdFromDict
}
}
}
Using Swift 3, you can access the dictionary value the following way:
var rollStatusArray = NSMutableArray()
for statusDict in rollStatusArray{
if statusId == "\((statusDict as! NSDictionary)["mark_status_id"]!)"{
return "\((statusDict as! NSDictionary)["mark_status_name"]!)"
}
}
I'm hoping to write a Swift dictionary extension that will append the reliably same data that eventually gets passed into a web request as URL params. I've tried various tricks, none seem to work.
The closest i've gotten is:
extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject {
mutating func auth() -> Dictionary {
self.updateValue("2.0", forKey: "api")
return self
}
}
But this is still throwing the error:
Cannot invoke 'updateValue' with an argument list of type '(String,
forKey:String)'
on the line that reads, "self.updateValue(..."
Any advice? Thanks in advance!
You just need to cast your string as! Value or as! Key. Also you have declared your method as mutating so you don't need to return anything.
extension Dictionary {
mutating func auth() {
updateValue("2.0" as! Value, forKey: "api" as! Key)
}
}
var dic: [String:AnyObject] = [:]
print(dic) // "[:]\n"
dic.auth()
print(dic) // "["api": 2.0]\n"
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"