Swift/iOS类中基于Core Data表实现非硬编码业务规则的方法咨询
在Swift/iOS中基于Core Data规则表实现业务决策
核心问题拆解
要替代硬编码的if/then逻辑,核心需要解决两个问题:
- 解析字符串形式的属性路径(如
joints.arm.wrist.left.y),获取类中对应变量的实际值 - 根据规则表的条件执行比较,再通过字符串路径设置类属性(如
self.elevated)
实现步骤
1. 定义Core Data规则实体
在Core Data中创建Rule实体,包含以下属性:
leftExpression: String(左属性路径,如joints.arm.wrist.left.y)condition: String(比较运算符,如>、<、==)rightExpression: String(右属性路径,如joints.shoulder.left.y)resultPath: String(目标属性路径,如elevated)resultValue: String(目标属性值,如true)
2. 实现动态属性访问工具
基于Swift Runtime实现通用的属性路径解析、取值和赋值方法(需确保业务类继承自NSObject):
import ObjectiveC extension NSObject { // 根据字符串路径获取属性值 func value(forPath path: String) -> Any? { let components = path.components(separatedBy: ".") var currentValue: Any? = self for component in components { guard let obj = currentValue as? NSObject else { return nil } currentValue = obj.value(forKey: component) } return currentValue } // 根据字符串路径设置属性值 func setValue(_ rawValue: String?, forPath path: String) { let components = path.components(separatedBy: ".") guard components.count > 0, let rawValue else { return } var currentObj: NSObject = self // 遍历到目标属性的父对象 for i in 0..<components.count - 1 { guard let nextObj = currentObj.value(forKey: components[i]) as? NSObject else { return } currentObj = nextObj } let targetKey = components.last! // 处理常见类型转换,可根据需求扩展 if let boolVal = Bool(rawValue) { currentObj.setValue(boolVal, forKey: targetKey) } else if let floatVal = Float(rawValue) { currentObj.setValue(floatVal, forKey: targetKey) } else { currentObj.setValue(rawValue, forKey: targetKey) } } }
3. 规则评估逻辑实现
在业务类中编写规则评估方法,读取Core Data中的规则并执行判断:
class MotionMonitor: NSObject { // 业务类变量(示例结构,需与实际代码对齐) var joints = Joints() var elevated = false // 模拟关节数据结构,需继承NSObject以支持Runtime访问 class Joints: NSObject { var shoulder = BodyPart() var arm = ArmPart() } class BodyPart: NSObject { var left = JointCoordinate() } class ArmPart: NSObject { var wrist = BodyPart() } class JointCoordinate: NSObject { var y: CGFloat = 0.0 } // 评估单条规则 func evaluateRule(_ rule: Rule) { // 获取左右表达式的数值 guard let leftVal = self.value(forPath: rule.leftExpression) as? CGFloat, let rightVal = self.value(forPath: rule.rightExpression) as? CGFloat else { return } // 判断条件是否满足 var conditionMet = false switch rule.condition { case ">": conditionMet = leftVal > rightVal case "<": conditionMet = leftVal < rightVal case "==": conditionMet = leftVal == rightVal // 可扩展支持>=、<=等运算符 default: return } // 满足条件则执行赋值操作 if conditionMet { self.setValue(rule.resultValue, forPath: rule.resultPath) print("warning") } } // 批量评估所有Core Data中的规则 func evaluateAllRules() { let fetchRequest: NSFetchRequest<Rule> = Rule.fetchRequest() guard let rules = try? CoreDataStack.shared.context.fetch(fetchRequest) else { return } rules.forEach(evaluateRule) } }
4. 关键注意事项
- 所有需要动态访问的类必须继承自
NSObject,否则无法使用value(forKey:)和setValue(_:forKey:)方法 - Core Data中存储的属性路径必须与业务类的属性名严格一致,避免拼写错误
- 类型转换逻辑需根据业务需求扩展,比如支持整数、字符串等更多类型
- 若需要支持复杂表达式(如包含计算),可考虑引入轻量表达式解析库,但简单属性比较场景下上述方案足够
内容的提问来源于stack exchange,提问作者iOScoder
相关产品推荐
相关产品推荐

