2016-12-08 4 views
1

私のアプリでは、データが同期されると、ローカルデバイスに同期させるべきサーバーから(与えられたタイムスタンプから)20kのエントリを得ることができます。すべてのエントリのために私はそれを(それがすでに存在する場合)を取得しようとすると私は新しいを作成しません。問題は、全体の操作が遅すぎるということです.iphone 5の20kは10+分です。しかし、もう1つの解決策は、指定されたタイムスタンプからすべてのエントリを削除し、すべての返されたエントリの新しいエントリを作成することで、すべての単一エントリに対してフェッチを実行する必要はありませんか?誰かがアドバイスを持っていればいいですね。ここでは、現在の状態のためのサンプルコードは、次のとおりです。ここでコアデータにエントリがあるかどうかを確認するより速い方法

var logEntryToUpdate:LogEntry! 
    if let savedEntry = CoreDataRequestHelper.getLogEntryByID(inputID: inputID, fetchAsync: true) { 
     logEntryToUpdate = savedEntry 
    } else { 
     logEntryToUpdate = LogEntry(entity: logEntryEntity!, insertInto: CoreDataStack.sharedInstance.saveManagedObjectContext) 
    } 
    logEntryToUpdate.populateWithSyncedData(data: row, startCol: 1) 

は、実際の要求方法であって、私が試した

class func getLogEntryByID(inputID:Int64, fetchAsync:Bool) ->LogEntry? { 

    let logEntryRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "LogEntry") 
    logEntryRequest.predicate = NSPredicate(format: "inputId == %@", NSNumber(value: inputID as Int64)) 
    logEntryRequest.fetchLimit = 1 

    do { 
     let mocToFetch = fetchAsync ? CoreDataStack.sharedInstance.saveManagedObjectContext : CoreDataStack.sharedInstance.managedObjectContext 
     if let fetchResults = try mocToFetch.fetch(logEntryRequest) as? [LogEntry] { 
      if (fetchResults.count > 0) { 
       return fetchResults[0] 
      } 
      return nil 
     } 
    } catch let error as NSError { 
     NSLog("Error fetching Log Entries by inputID from core data !!! \(error.localizedDescription)") 
    } 

    return nil 

} 

もう一つは、特定の要求のための数を確認することですが、再び遅すぎます。

class func doesLogEntryExist(inputID:Int64, fetchAsync:Bool) ->Bool { 

    let logEntryRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "LogEntry") 
    logEntryRequest.predicate = NSPredicate(format: "inputId == %@", NSNumber(value: inputID as Int64)) 
    //logEntryRequest.resultType = .countResultType 
    logEntryRequest.fetchLimit = 1 

    do { 
     let mocToFetch = fetchAsync ? CoreDataStack.sharedInstance.saveManagedObjectContext : CoreDataStack.sharedInstance.managedObjectContext 
     let count = try mocToFetch.count(for: logEntryRequest) 
     if (count > 0) { 
      return true 
     } 
     return false 
    } catch let error as NSError { 
     NSLog("Error fetching Log Entries by inputID from core data !!! \(error.localizedDescription)") 
    } 

    return false 

} 
+2

代わりの時に各潜在的な試合、1を取得し、なぜ「ドンすべての既存のID(またはコアデータのフィールドがある場合はタイムスタンプ以来のすべて)を配列またはセットにロードします。20,000の8バイトの識別子は160KBで、個々のフェッチよりもはるかに高速にメモリ内を検索できます大きなデータセット。 – Paulw11

+0

@ Paulw11ありがとうございました!あなたの方法は私の輸入品を悲鳴にさせました!ありがとうございました。 – Adrian

答えて

3

インスタンスをフェッチしても、カウントを取得しても、受信レコードごとに1つのフェッチ要求が行われます。それは遅くなるでしょうし、あなたのコードはフェッチを実行する時間のほとんどすべてを費やしています。

改善点の1つは、フェッチ数を減らすためにレコードをバッチアップすることです。配列に複数のレコードIDを取得して、その後見つかったIDを確認するために、フェッチの結果を経る

NSPredicate(format: "inputId IN %@", inputIdArray) 

のような述語を一度にそれらのすべてを取得します。配列内の50または100のIDを累積すると、フェッチ数が50倍または100倍に減少します。

タイムスタンプのすべてのエントリを削除してから再挿入すると良いかもしれませんが、予測は困難です。 20,000をすべて挿入する必要があります。それはフェッチの数を減らすよりも速いか遅いのですか?確かに言うことは不可能です。

0

Paulw11のコメントに基づいて、Structsがコアデータにインポートされることを評価する次の方法を考え出しました。

私の例では、検索語を格納するクラスがあります。検索クラス内で、私の構造体配列内のものの値を記述する述語を作成します。 recordsInCoreDataをインスタンス化する

func importToCoreData(dataToEvaluateArray: [YourDataStruct]) { 
    // This is what Paul described in his comment 
    let newDataToEvaluate = Set(dataToEvaluateArray.map{$0.id}) 
    let recordsInCoreData = getIdSetForCurrentPredicate() 
    let newRecords = newDataToEvaluate.subtracting(recordsInCoreData) 
    // create an empty array 
    var itemsToImportArray: [YourDataStruct] = [] 

    // and dump records with ids contained in newRecords into it 
    dataToEvaluateArray.forEach{ record in 
     if newRecords.contains(record.id) { 
     itemsToImportArray.append(record) 
     } 
    } 

    // THEN, import if you need to 
    itemsToImportArray.forEach { struct in 
     // set up your entity, properties, etc. 
    } 

    // Once it's imported, save 
    // You can save each time you import a record, but it'll go faster if you do it once. 
    do { 
     try self.managedObjectContext.save() 
    } catch let error { 
     self.delegate?.errorAlert(error.localizedDescription, sender: self) 
    } 

    self.delegate?.updateFetchedResultsController() 
} 

は、私がmanagedObjectContextに存在するユニークな識別子のセットを返します。この方法で、作成した:

func getIdSetForCurrentPredicate() -> Set<String> { 
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "YourEntity") 
    // searchQuery is a class I created with a computed property for a creating a predicate. You'll need to write your own predicate 
    fetchRequest.predicate = searchQuery.predicate 

    var existingIds: [YourEntity] = [] 

    do { 
     existingIds = try managedObjectContext.fetch(fetchRequest) as! [YourEntity] 
    } catch let error { 
     delegate?.errorAlert(error.localizedDescription, sender: self) 
    } 

    return Set<String>(existingIds.map{$0.id}) 
    } 
関連する問題