使用后台线程

时间:2016-03-14 17:23:27

标签: swift multithreading csv core-data grand-central-dispatch

在使用后台线程上的Core Data在OS X中导入大型.csv文件时遇到了一些麻烦。

我的简化数据模型是一个数据集,它与许多条目有很多关系。每个条目都是.csv文件中的一行(其中包含一些我为了简洁而遗漏的属性)。根据我所读到的关于有效导入大量数据的内容,以及如何使进度指示器正常工作,我创建了一个托管对象上下文,以便进行导入。

我遇到两件事有困难:

  1. 我需要在导入结束时继续引用新数据集,因为我需要在弹出窗口中选择它。这将在主线程中完成,但为了提高效率(并使我的NSProgressIndicator工作),新的数据集在后台线程上创建,背景为MOC。

  2. 根据我的阅读,批量导入,以便后台MOC保存和重置,是阻止导入占用过多内存的最佳方法。到目前为止情况并非如此 - 看起来即使是数十兆字节的文件也会使用内存演出。此外,一旦我重置了导入MOC,它就无法找到inDataset的数据,因此无法在所有后续条目和数据集之间创建关系。

  3. 我已经发布了以下简化代码。我尝试过refreshObject:mergeChanges,没有很好的结果。谁能指出我做错了什么?

    let inFile  = op.URL
    dispatch_async(dispatch_get_global_queue(priority, 0)) {
    
    
                //create moc
                let inMOC = NSManagedObjectContext()
                inMOC.undoManager = nil
                inMOC.persistentStoreCoordinator = self.moc.persistentStoreCoordinator
    
    
    
    
                var inDataset :  inDataset = Dataset(entity: NSEntityDescription.entityForName("Dataset", inManagedObjectContext: inMOC)!, insertIntoManagedObjectContext: inMOC)
    
                //set up NSProgressIndicator here, removed for clarity
    
                let datasetID = inDataset.objectID
                mocDataset = self.moc.objectWithID(datasetID) as! Dataset
    
    
    
                let fileContents : String = (try! NSString(contentsOfFile: inFile!.path!, encoding: NSUTF8StringEncoding)) as String
                let fileLines : [String] = fileContents.componentsSeparatedByString("\n")
    
    
    
                var batchCount : Int = 0
    
                for thisLine : String in fileLines {
                    let newEntry : Entry = Entry(entity: NSEntityDescription.entityForName("Entry", inManagedObjectContext: inMOC)!, insertIntoManagedObjectContext: inMOC)
                    //Read in attributes of this entry from this line, removed here for brevity
                    newEntry.setValue("Entry", forKey: "type")
                    newEntry.setValue(inDataset, forKey: "dataset")
                    inDataset.addEntryObject(newEntry)
    
    
                    dispatch_async(dispatch_get_main_queue()) {          
                        self.progInd.incrementBy(1)
                    }
    
    
                    batchCount++
                    if(batchCount > 1000){
                        do {
                            try inMOC.save()
                        } catch let error as NSError {
                            print(error)
                        } catch {
                            fatalError()
                        }
                        batchCount = 0
                        inMOC.reset()
    
                       inDataset = inMOC.objectWithID(datasetID) as! Dataset
                     //   fails here, does not seem to be able to find the data associated with inDataset
    
                    }
    
                }// end of loop for reading lines
    
    
                    //save whatever remains after last batch save
                    do {
                        try inMOC.save()
                    } catch let error as NSError {
                        print(error)
                    } catch {
                        fatalError()
                    }
    
    
                   inMOC.reset()
    
    
                    dispatch_async(dispatch_get_main_queue()) {
                        //This is done on main queue after background queue has read all line
                        // I thought the statement just below would refresh mocDataset, but no luck
                       self.moc.refreshObject(mocDataset, mergeChanges: true)
    
    
                        //new dataset selected from popup
    
    
                        let datafetch = NSFetchRequest(entityName: "Dataset")
                        let datasets : [Dataset] = try! self.moc.executeFetchRequest(datafetch) as! [Dataset]
                        self.datasetController.addObjects(datasets)
                        let mocDataset = self.moc.objectWithID(datasetID) as! Dataset
                        //fails here too, mocDataset object has data as a fault
                        let nDarray : [Dataset] = [mocDataset]
                        self.datasetController.setSelectedObjects(nDarray)
    
                    }
    
    
            }
    

0 个答案:

没有答案