Xcode CoreData:循环中从一个实体取值插入另一实体的实现方法
问题修正与实现方案
首先明确一个核心错误:@FetchRequest 是 SwiftUI 专用的属性包装器,仅支持在 SwiftUI 视图结构中声明,无法在普通业务函数内使用。你需要用 CoreData 原生的 NSFetchRequest 执行手动条件查询。
基础实现(适合少量数据场景)
你不需要分开写getLat和getLon两个函数,同一个机场编码查询两次属于冗余操作,直接写一个统一的查询函数,一次查询同时返回经纬度即可:
// 传入机场编码和上下文,返回(纬度, 经度)的可选元组 func getCoordinateFor(airportCode: String, context: NSManagedObjectContext) -> (lat: String, lon: String)? { let fetchRequest: NSFetchRequest<AllAirports> = AllAirports.fetchRequest() // 加谓词匹配airport_code,精确查询 fetchRequest.predicate = NSPredicate(format: "airport_code == %@", airportCode) fetchRequest.fetchLimit = 1 // 因为airport_code唯一,只取第一条即可提升性能 do { let result = try context.fetch(fetchRequest) if let matchedAirport = result.first { return (matchedAirport.lat, matchedAirport.lon) } else { // 没有匹配到对应编码的机场,可自行处理默认值 return nil } } catch { print("查询机场坐标失败: \(error.localizedDescription)") return nil } }
然后修改你的saveData函数,在循环里调用上述函数即可:
func saveData(context: NSManagedObjectContext){ xArray.forEach { (data) in let entity = Airports(context: context) entity.airport_code = data.airport_code entity.access_points = data.access_points entity.image_url = data.image_url // 查询当前机场的坐标 if let coordinate = getCoordinateFor(airportCode: data.airport_code, context: context) { entity.lat = coordinate.lat entity.lon = coordinate.lon } else { // 无匹配时可赋值默认值,比如空字符串 entity.lat = "" entity.lon = "" } } do{ try context.save() print("Success Saving to CoreData: \(xArray.count)") } catch{ print("Error Saving to CoreData \(error.localizedDescription)") } }
性能优化实现(适合xArray数据量较大的场景)
如果你的xArray有几十上百条甚至更多数据,循环内每次执行数据库查询会有明显的性能损耗,可以改为一次性批量查询所有需要的坐标,存为字典后再循环赋值,能大幅提升执行效率:
func saveData(context: NSManagedObjectContext){ // 先取出所有需要查询的机场编码 let allCodes = xArray.map { $0.airport_code } // 一次性查询所有匹配的AllAirports记录 let fetchRequest: NSFetchRequest<AllAirports> = AllAirports.fetchRequest() fetchRequest.predicate = NSPredicate(format: "airport_code IN %@", allCodes) var codeToCoordinate: [String: (lat: String, lon: String)] = [:] do { let results = try context.fetch(fetchRequest) // 遍历查询结果,转成【编码: 坐标】的字典 results.forEach { airport in guard let code = airport.airport_code else { return } codeToCoordinate[code] = (airport.lat, airport.lon) } } catch { print("批量查询机场坐标失败: \(error.localizedDescription)") } // 循环赋值,直接从字典取值,不需要再查数据库 xArray.forEach { data in let entity = Airports(context: context) entity.airport_code = data.airport_code entity.access_points = data.access_points entity.image_url = data.image_url let coordinate = codeToCoordinate[data.airport_code] entity.lat = coordinate?.lat ?? "" entity.lon = coordinate?.lon ?? "" } do{ try context.save() print("Success Saving to CoreData: \(xArray.count)") } catch{ print("Error Saving to CoreData \(error.localizedDescription)") } }
内容的提问来源于stack exchange,提问作者CrewFly
相关产品推荐
相关产品推荐

