【问题标题】:setValuesForKeysWithDictionary in Swift 4?Swift 4 中的 setValuesForKeysWithDictionary?
【发布时间】:2026-01-22 15:25:01
【问题描述】:

似乎 Swift 4 正在实现与 (void)setValuesForKeysWithDictionary() 不同的方法,在 Swift 4 中这个函数的合适替代品是什么?

我有结构

struct User {
    let name: String?
    let email: String?
}

dictionaryOfUsers 来自数据结构,其值根据数据库中的用户数量动态呈现:

let dictionaryOfUsers = [{key1: "name1", key2 : "name1@xyz.com"}, {key1 : "name2", key2 : "name2@gmail.com"} ]   
let users = [User]

现在我想使用这个函数来创建我的用户数组以在 Swift 4 中创建字典:

for dictionary in dictionaryOfUsers {
    let user = User()
    user.setValuesForKeysWithDictionary(dictionary) 

并附加到用户

    users.append(user)
}     

【问题讨论】:

  • key1key2 代表什么?我希望 ”name” 和 '”email” 改为字符串......
  • 是的 key1 和 key2 用于“姓名”和“电子邮件”

标签: ios swift swift4 key-value-coding keypaths


【解决方案1】:

试试这个方法:

func setValuesForKeys(_ keyedValues: [String : Any])

使用给定字典中的值设置接收器的属性,使用它的键来标识属性。默认实现为每个键值对调用setValue(_:forKey:)...

您的代码有许多小问题 - 以及一些主要问题(有关详细信息,请参阅 matt 答案)。无论如何,我认为这应该完成你所追求的:

import Foundation

class User: NSObject {
    @objc var name: String!
    @objc var email: String!
}

let dictionaryOfUsers = [
    ["name": "name1", "email": "name1@xyz.com"],
    ["name": "name2", "email": "name2@gmail.com"]
]

var users = [User]()
for dictionary in dictionaryOfUsers {
    let user = User()
    user.setValuesForKeys(dictionary) 
    users.append(user)
} 

【讨论】:

  • 我想将字典作为单个对象传递给方法,而不是传递键值对 func setValuesForKeys( _ keyedValues : [String : Any])
  • @AshimDahal 我相信这就是你所追求的。 [String: Any] 类型只是 Dictionary<String, Any> 的语法糖。如果这仍然不起作用,请改进您的问题,显示更多代码,以便我们进一步为您提供帮助。
  • @AshimDahal 刚刚让我想到还有另一个(优雅的!)解决方案使用 Swift 4、结构和没有键路径;)如果我有时间,我会尝试在今天晚些时候发布它......跨度>
  • 你认为有什么其他方法可以解决这个问题吗?@@PauloMattos
  • 我能找到的一件事是,如果您的对象模型符合@objc。那么你可以直接使用。 user.setValuesForKeys(dictionaryOfUsers)。而不是通过循环运行
【解决方案2】:

问题是您正试图在 struct 上使用 Cocoa 键值编码(setValuesForKeys(_:) 的来源)。你不能那样做。 Cocoa 是 Objective-C; Objective-C 不知道 Cocoa 结构是什么。您需要 User 是从 NSObject 派生的 @objc 类,并且它的所有属性也需要公开为 @objc

或者,使用新的 Swift 4 键路径功能,它可以通过键访问结构属性。示例:

struct User {
    var name: String?
    var email: String?
}

let arrayOfDicts = [
    [\User.name: "name1", \User.email : "name1@xyz.com"],
    [\User.name : "name2", \User.email : "name2@gmail.com"]
]

for d in arrayOfDicts {
    var user = User()
    for key in d.keys {
        user[keyPath:key] = d[key]!
    }
    print(user)
}
/*
 User(name: Optional("name1"), email: Optional("name1@xyz.com"))
 User(name: Optional("name2"), email: Optional("name2@gmail.com"))
*/

【讨论】:

  • 这给了我错误“类型没有下标成员”
  • @fullMoon 那么你没有按照我说的去做。将我的答案中的代码复制并粘贴到 Swift 4 项目中并运行它。有用。 (例如,一个典型的错误是你拼错了keyPath。但这不是我的错。我拼错了。)
  • 我希望我能投票 10 次!我在所有变量之前添加了@objc,瞧!就是这张票!谢谢!
【解决方案3】:

不用说 Swift 4 没有 setValuesForKeysWithDictionary 方法。此外,当前的 setValuesForKeys 方法在最新的 Xcode 版本的 Swift 4 中经常失败。

我的用户对象如下。

import UIKit

class User: NSObject {
    var name: String?
    var email: String?
}

我自己解决这个问题的方法是手动添加键作为 NSDictionary,如下所示。

let user = User()
user.email = (snapshot.value as? NSDictionary)?["email"] as? String ?? ""
user.name = (snapshot.value as? NSDictionary)?["name"] as? String ?? ""
print(user.email as Any)
print(user.name as Any)

它可以正常工作。试试看吧。

【讨论】:

    【解决方案4】:

    我正在做某事。万一有帮助... P.S:请使用泛型对其进行优化。

      import Foundation
      import CoreData
    
       enum ModelInitializationResult {
       case none
       case completedWithoutErrors
       case completedWithNullDataErrors
       case completedWithNoSuchKeyErrors
        }
    
     extension NSManagedObject {
    
     //Note: For this to work, the keys in the dictionary should be same as attibute name of this class
    func initializeModelFromDictionary(dictionary: [String:Any] )  -> ModelInitializationResult{
      var completionResult = ModelInitializationResult.none
    
      let modelAttributes = self.entity.attributesByName
      let modelAttributeKeys = modelAttributes.keys
    
      for case let (keyToSet, valueToSet) in dictionary {
        //check for invalid key
          guard modelAttributeKeys.contains(keyToSet) else{
              completionResult = .completedWithNoSuchKeyErrors
              continue;
          }
    
          //check valueToSetType for Null
          let valueToSetType = type(of: valueToSet)
          guard valueToSetType != NSNull.self else{
              print("ERROR: Found NSNUll for value to set")
              completionResult = .completedWithNullDataErrors
              continue;
          }
    
          //Check desiredType ; set value for defined types
          let modelAttributeValue = modelAttributes[keyToSet]
          let modelAttributeType = modelAttributeValue?.attributeType
    
        switch (modelAttributeType!) {
          case .undefinedAttributeType :
              print("Error : undefinedAttributeType")
          case .integer16AttributeType, .integer32AttributeType, .integer64AttributeType :
              if let anInt = valueToSet as? Int{
                  self.setValue(anInt, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
          case .stringAttributeType :
              if let anString = valueToSet as? String{
                  self.setValue(anString, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
          case .booleanAttributeType :
              if let aBool = valueToSet as? Bool{
                  self.setValue(aBool, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
          case .dateAttributeType :
              if let aDate = valueToSet as? Date{
                  self.setValue(aDate, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
          case .binaryDataAttributeType :
              if let aData = valueToSet as? Data{
                  self.setValue(aData, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
    
          case .transformableAttributeType :// If your attribute is of NSTransformableAttributeType,
              //print(Pretty//printedFunction(), "desiredType : transformableAttributeType")
              if let anObject = valueToSet as? NSObject {
                  self.setValue(anObject, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
    
          case .doubleAttributeType :
              //print(Pretty//printedFunction(), "desiredType : doubleAttributeType")
              if let anObject = valueToSet as? Double {
                  self.setValue(anObject, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
          case .floatAttributeType :
              //print(Pretty//printedFunction(), "desiredType : floatAttributeType")
              if let anObject = valueToSet as? Float {
                  self.setValue(anObject, forKey: keyToSet)
              }
              else{
                  //print(Pretty//printedFunction(),"Error  in setting value for key:\(keyToSet) Incompatible type")
              }
          case .decimalAttributeType :
              print("Error: Data type decimalAttributeType Not handled\(String(describing: modelAttributeType))")
          case .objectIDAttributeType:
              print("Error: Data type transformableAttributeType Not handled\(String(describing: modelAttributeType))")
          default :
              print("ERROR : \(String(describing: modelAttributeType))")
          }
      }
      return completionResult
    }
    
    func toDictionary() -> [String:Any]     {
        let keys = Array(self.entity.attributesByName.keys)
        let dict = self.dictionaryWithValues(forKeys: keys)
        return dict
    }
    
    func printAllValues (){
        for key in self.entity.attributesByName.keys{
            let value: Any? = self.value(forKey: key)
            print("\(key) = \(String(describing: value))")
        }
    }
    

    }

    【讨论】: