0

先週、Apple のエンジニアにメールでNSMetadataQuery.

メールは次のとおりです。

やあ、

ドキュメント ベースのアプリまたは iOS を作成していますが、名前を変更する (ドキュメントを新しい場所に移動する) メソッドが、実行中の NSMetadataQuery と競合しているようです。

move メソッドが呼び出された後、クエリは数回更新されます。最初は移動したばかりのアイテムの古い URL を持ち、次は新しい URL を持ちます。ただし、更新後に URL が削除された場合の更新方法 (以下) により、モデルは削除された URL を削除し、まだ存在しない URL が見つかった場合はその逆を行います。

私の問題は 2 つの問題のうちの 1 つであると思います。NSMetadataQuery の更新方法が不十分であり、項目の URL を削除する前に「正しい」属性をチェックしていないかのいずれかです (ドキュメントを見ても、私が示唆するようなものは何も表示されません)。 m 何かが足りない) または私の名前変更方法が本来あるべきことをしていません。

名前変更メソッドの開始時に更新を無効にし、すべての完了ブロックが終了したら再度有効にしようとしましたが、違いはありません。

私の NSMetadataQuery の update メソッド:

func metadataQueryDidUpdate(notification: NSNotification) {
    ubiquitousItemsQuery?.disableUpdates()

    var ubiquitousItemURLs = [NSURL]()

    if ubiquitousItemsQuery != nil && UbiquityManager.sharedInstance.ubiquityIsAvailable {
        for var i = 0; i < ubiquitousItemsQuery?.resultCount; i++ {
            if let result = ubiquitousItemsQuery?.resultAtIndex(i) as? NSMetadataItem {
                if let itemURLValue = result.valueForAttribute(NSMetadataItemURLKey) as? NSURL {
                    ubiquitousItemURLs.append(itemURLValue)
                }
            }
        }

        //  Remove deleted items
        //
        for (index, fileRepresentation) in enumerate(fileRepresentations) {
            if fileRepresentation.fileURL != nil && !contains(ubiquitousItemURLs, fileRepresentation.fileURL!) {
                removeFileRepresentations([fileRepresentation], fromDisk: false)
            }
        }

        //  Load documents
        //
        for (index, fileURL) in enumerate(ubiquitousItemURLs) {
            loadDocumentAtFileURL(fileURL, completionHandler: nil)
        }

        ubiquitousItemsQuery?.enableUpdates()
    }
}

そして私の名前変更方法:

func renameFileRepresentation(fileRepresentation: FileRepresentation, toNewNameWithoutExtension newName: String) {
    if fileRepresentation.name == newName || fileRepresentation.fileURL == nil || newName.isEmpty {
        return
    }

    let newNameWithExtension = newName.stringByAppendingPathExtension(NotableDocumentExtension)!

    //  Update file representation
    //
    fileRepresentation.nameWithExtension = newNameWithExtension

    if let indexPath = self.indexPathForFileRepresentation(fileRepresentation) {
        self.reloadFileRepresentationsAtIndexPaths([indexPath])
    }

    UbiquityManager.automaticDocumentsDirectoryURLWithCompletionHandler { (documentsDirectoryURL) -> Void in
        let sourceURL = fileRepresentation.fileURL!
        let destinationURL = documentsDirectoryURL.URLByAppendingPathComponent(newNameWithExtension)

        //  Update file representation
        //
        fileRepresentation.fileURL = destinationURL

        if let indexPath = self.indexPathForFileRepresentation(fileRepresentation) {
            self.reloadFileRepresentationsAtIndexPaths([indexPath])
        }

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
            let coordinator = NSFileCoordinator(filePresenter: nil)
            var coordinatorError: NSError?

            coordinator.coordinateWritingItemAtURL(sourceURL, options: .ForMoving, writingItemAtURL: destinationURL, options: .ForReplacing, error: &coordinatorError, byAccessor: { (newSourceURL, newDestinationURL) -> Void in
                var moveError: NSError?
                let moveSuccess = NSFileManager().moveItemAtURL(newSourceURL, toURL: newDestinationURL, error: &moveError)

                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    assert(moveError == nil || moveSuccess, "Error renaming (moving) document from \(newSourceURL) to \(newDestinationURL).\nSuccess? \(moveSuccess).\nError message: \(moveError).")

                    if let query = self.ubiquitousItemsQuery {
                        query.enableUpdates()
                    }

                    if moveError != nil || moveSuccess {
                        // TODO: Implement resetting file rep
                    }
                })
            })
        })
    }
}

ほぼ即座に返信がありましたが、それ以降、返信はありません。

返信はこちら

私が思いつく大きなことの 1 つは、disableUpdates() と enableUpdates() の使い方です。実行ループの同じターンで両方を実行していますが、NSMetadataQuery は結果を非同期に配信します。このコードは更新通知内で実行されるため、クエリに対して同期的に実行されます。したがって、クエリの観点からは、通知を投稿することで更新の配信を開始します。通知の投稿は同期プロセスであるため、通知の投稿中は更新が無効になり、再度有効になります。したがって、クエリが通知の送信を完了するまでには、結果の配信を開始したときとまったく同じ状態に戻ります。それはあなたが望んでいる動作ではないようです。

ここで助けが必要です

NSMetadataQuery には、更新が無効になっている間に結果を追加するある種のキャッシュがあり、有効にすると、それらの (おそらく多くの) キャッシュ結果がループされ、それぞれが更新通知を介して送信されると仮定しました。

とにかく、私は iOS で実行ループを調べました。自分でできる限り理解していますが、返信がどのように役立つか、つまり実際に問題を解決する方法、または問題の原因さえ理解していません。 .

誰かが何か良いアイデアを持っているなら、私はあなたの助けが大好きです!

ありがとう。

アップデート

関数の開始時と終了時のログは次のとおりです。

start metadataQueryDidUpdate:
end metadataQueryDidUpdate:
start metadataQueryDidUpdate:
end metadataQueryDidUpdate:
start renameFileRepresentation:toNewNameWithoutExtension
start metadataQueryDidUpdate:
end metadataQueryDidUpdate:
end renameFileRepresentation:toNewNameWithoutExtension
start metadataQueryDidUpdate:
end metadataQueryDidUpdate:
start metadataQueryDidUpdate:
end metadataQueryDidUpdate:
start metadataQueryDidUpdate:
end metadataQueryDidUpdate:
4

1 に答える 1

0

私は同じ問題を抱えていました。NSMetaDataQuery の更新は、変更があるかどうかを通知しますが、その変更が何であったかは通知しません。変更が名前の変更である場合、以前の名前を特定する方法がないため、tableView で古いエントリを見つけることができます。とてもイライラします。

ただし、NSFileCoordinator と NSFilePresenter を使用して情報を取得できます。

NSFilePresenter メソッドを使用して presentedSubitemAtURL(oldURL: NSURL, didMoveToURL newURL: NSURL)

ご指摘のとおり、クエリ変更通知は古い URL で 1 回、新しい URL で 1 回呼び出されます。上記のメソッドは、これら 2 つの通知の間に呼び出されます。

于 2014-10-26T18:43:42.443 に答える