Swift中Operation间如何传递数据?我的实现遇异常
Swift Operation队列中操作间数据传递失败问题解决
问题描述
我正在学习Swift的Operation相关内容,能将一系列操作加入队列运行,但操作间传递数据时遇到问题:getVOOCSVData操作能正确获取数据(可通过其completionBlock中的打印语句确认),但后续的convertStringToArray操作运行时传入的数据为空。
原代码
操作配置代码
// operation setup struct VOOModel { init() { let operationQueue = OperationQueue() let checkForUpdatedVOOData = IsUpdatedVOODataAvailable() checkForUpdatedVOOData.completionBlock = { print("Updated CSV Data = \(checkForUpdatedVOOData.updatedCSVData)") print("Latest Date = \(checkForUpdatedVOOData.latestCSVDate)") } let getVOOCSVData = GetVOOCSVData() getVOOCSVData.addDependency(checkForUpdatedVOOData) getVOOCSVData.completionBlock = { print("completion block get voo csv data") print("\(getVOOCSVData.csvData)") // prints out all of the data correctly } let convertStringToArray = ConvertStringToArray2(csvData: getVOOCSVData.csvData) convertStringToArray.addDependency(getVOOCSVData) convertStringToArray.completionBlock = { print("completion block convert string to array") } operationQueue.addOperations([checkForUpdatedVOOData, getVOOCSVData, convertStringToArray], waitUntilFinished: true) } // end init } // end structure
ConvertStringToArray2类实现
// operation class final class ConvertStringToArray2: Operation { var localData: String var sortedDataArray : [IndexFund] = [] init(csvData: String) { localData = csvData } override func main() { var dataArray = [IndexFund]() var rows = localData.components(separatedBy: "\n") // gives rows a value of 1 rows.removeFirst() for row in rows { let columns = row.components(separatedBy: ",") if columns.count == 6 { let theDate = columns[0].replacingOccurrences(of: "-", with: "") let timeStamp = stringDateFormatter.date(from: theDate)! let open = Double(columns[1])! let high = Double(columns[2])! let low = Double(columns[3])! let close = Double(columns[4])! let theVolume = columns[5].trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) let volume = Int64(theVolume) let fundValuesByDay = IndexFund( timeStamp: timeStamp, open: open, high: high, low: low, close: close, volume: volume!) dataArray.append(fundValuesByDay) } sortedDataArray = dataArray.sorted { $0.timeStamp < $1.timeStamp } } } }
问题原因
初始化ConvertStringToArray2时直接传入getVOOCSVData.csvData,此时getVOOCSVData还未执行,csvData是空值。虽然通过addDependency保证了操作执行顺序,但初始化是同步完成的,依赖机制不影响初始化阶段的参数传递。
解决方案
方案一:修改操作类,持有前序操作引用
修改ConvertStringToArray2,让它持有getVOOCSVData的弱引用,在main方法中获取已赋值的数据:
final class ConvertStringToArray2: Operation { weak var csvDataOperation: GetVOOCSVData? var sortedDataArray : [IndexFund] = [] init(operation: GetVOOCSVData) { csvDataOperation = operation super.init() } override func main() { guard let localData = csvDataOperation?.csvData, !localData.isEmpty else { print("CSV数据为空,无法转换") return } var dataArray = [IndexFund]() let rows = localData.components(separatedBy: "\n").dropFirst() for row in rows { let columns = row.components(separatedBy: ",") guard columns.count == 6, let timeStamp = stringDateFormatter.date(from: columns[0].replacingOccurrences(of: "-", with: "")), let open = Double(columns[1]), let high = Double(columns[2]), let low = Double(columns[3]), let close = Double(columns[4]), let volume = Int64(columns[5].trimmingCharacters(in: .whitespacesAndNewlines)) else { continue } let fundValuesByDay = IndexFund( timeStamp: timeStamp, open: open, high: high, low: low, close: close, volume: volume ) dataArray.append(fundValuesByDay) } sortedDataArray = dataArray.sorted { $0.timeStamp < $1.timeStamp } } }
同时修改操作初始化代码:
let convertStringToArray = ConvertStringToArray2(operation: getVOOCSVData) convertStringToArray.addDependency(getVOOCSVData)
方案二:在前序操作完成后创建后续操作
修改getVOOCSVData的completionBlock,在数据准备完成后再创建并添加convertStringToArray操作:
struct VOOModel { init() { let operationQueue = OperationQueue() let checkForUpdatedVOOData = IsUpdatedVOODataAvailable() checkForUpdatedVOOData.completionBlock = { print("Updated CSV Data = \(checkForUpdatedVOOData.updatedCSVData)") print("Latest Date = \(checkForUpdatedVOOData.latestCSVDate)") } let getVOOCSVData = GetVOOCSVData() getVOOCSVData.addDependency(checkForUpdatedVOOData) getVOOCSVData.completionBlock = { print("completion block get voo csv data") print("\(getVOOCSVData.csvData)") guard !getVOOCSVData.csvData.isEmpty else { return } let convertStringToArray = ConvertStringToArray2(csvData: getVOOCSVData.csvData) convertStringToArray.completionBlock = { print("completion block convert string to array") } operationQueue.addOperation(convertStringToArray) } operationQueue.addOperations([checkForUpdatedVOOData, getVOOCSVData], waitUntilFinished: true) } }
注意事项
- 操作间传递数据时,避免在初始化阶段直接依赖未执行操作的属性,因为初始化是同步的,此时属性值还未被赋值
- 方案一中使用
weak引用前序操作,避免循环引用导致内存泄漏 - 方案二更灵活,确保只有前序操作完成且数据有效时才创建后续操作
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

