Search code examples
iosswiftnsdictionarynsuserdefaults

"Cannot subscript a value of type 'Dictionary<NSObject, AnyObject>' with an index of type 'String" error


I been working on a project that needs to restore the saved data from .plist, but I am encountering an error Cannot subscript a value of type 'Dictionary' with an index of type 'String' in my code. I am trying to solve it but unfortunately I don't know how. I tried some solution I got here in stackoverflow but It didn't worked out. Please help me with this because It is my first time to create a function to restore data. Thank you

error here

 @objc func restoreSucceed() {
    performSelector(inBackground: #selector(stopIndicator), with: nil)
    //エラーアラートビューの表示
    let alertController = UIAlertController(title: "", message: "リストアが完了しました \n (Restore completed)", preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "OK", style: .default))
    self.present(alertController, animated: true, completion: nil)

    if floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1 {
        var pref = UserDefaults.standard
        //ローカルplist格納先を取得
        let strWorkPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0]
        let strPlistPath = "\(strWorkPath)/\(S_DIRECTORY_NAME)/\(S_PLIST_NAME)"
        let dicPref = NSDictionary(contentsOfFile: strPlistPath) as Dictionary?
        if let key1 = (dicPref as NSDictionary?)?.keyEnumerator() {
            for key in key1 {
                let strKey = key as? String
                pref.set(dicPref?[strKey ?? ""], forKey: strKey ?? "")
            }
        }
        pref.synchronize()
    }

    navigationController?.popViewController(animated: true)
}

Solution

  • Your code uses a lot of inappropriate objective-c-ish API.

    This is the recommended Swift way to read and parse a property list file

    if #available(iOS 7.1, *) {   
        //ローカルplist格納先を取得
        do {
            let strWorkURL = try FileManager.default.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            let strPlistURL = strWorkURL.appendingPathComponent("\(S_DIRECTORY_NAME)/\(S_PLIST_NAME)")
            let strPlistData = try Data(contentsOf: strPlistURL)
            guard let dicPref = try PropertyListSerialization.propertyList(from: strPlistData, format: nil) as? [String:Any] else { return }
            for (key, value) in dicPref {
                UserDefaults.standard.set(value, forKey: key)
            }
        } catch { print(error) }
    }
    

    And don't use performSelector(inBackground:) either. Use GCD

    DispatchQueue.global().async {
        stopIndicator()
    }