Repository navigation
ファイル辞書のメモリリークを修正 - #544
Merged
Merged
ファイル辞書のメモリリークを修正#544
Conversation
NSFileCoordinatorは登録したファイルプレゼンターを強参照で保持するため、 FileDictが自分自身を登録してdeinitで解除する作りでは解放されず、 辞書の無効化やエンコーディング変更、saveToUserDictの変更のたびに古い辞書がリークしていた。 また、saveToUserDictを変更したあとの辞書はファイルの変更を受け取れていなかった。 辞書フォルダを監視しているUserDictが、フォルダ内のファイルの変更をその時点のFileDictに伝えるようにする。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
設定画面で辞書を有効・無効にしたり、エンコーディングや「変換候補をユーザー辞書に保存する」の設定を変えたりするたびに、古い
FileDictが解放されずに残ってしまうメモリリークがありました。この問題を修正します。原因
FileDictは init でNSFileCoordinator.addFilePresenter(self)を呼び、deinit でremoveFilePresenter(self)を呼んでいました。ですが
NSFileCoordinatorは登録されたNSFilePresenterを強参照で持つので、登録されている限り deinit は呼ばれず、解除もされません。あわせて、
with(saveToUserDict:)で作り直したFileDictはNSFilePresenterに登録されていませんでした。そのため、設定を変えたあとの辞書は外部での編集を受け取れず、通知はリークした古いインスタンスに届いていました。変更内容
FileDictをNSFilePresenterとして登録しないようにしました。登録簿からFileDictへの参照がなくなるので、解除し忘れや弱参照の付け忘れでリークすることもありません。UserDictが、presentedSubitemDidChange(at:)で辞書フォルダ内のファイルの変更を受けたときに、該当するFileDictのfileDidChange(modificationDate:)を呼ぶようにしました。dicts(またはユーザー辞書)からファイル名でFileDictを探します。そのため、with(saveToUserDict:)で置き換えたあとの辞書にも変更が届きます。notificationNameDictFileDidAppearを投げません(ファイル辞書の一覧に追加しないため)。with(saveToUserDict:)ではfileModificationDateを引き継ぐようにしました。自分の保存による変更をスキップする判定を、作り直したあとも正しく行うためです。load()/save()でNSFileCoordinatorに渡すファイルプレゼンターをnilにしました。これまで渡していたFileDict自身はもう登録していないので、挙動は変わりません。検討したほかの案
FileDictごとに専用のプレゼンター(FileDictを弱参照で持つ)を登録する案も考えました。リークは直りますが、弱参照に頼る作りになります。また、withで作り直すたびに、古いインスタンスが解放されるまでは同じファイルを2つのNSFilePresenterが監視することになるので採用しませんでした。今後の課題
UserDict側に外部の辞書ごとのプレゼンターを持たせる必要があります。テスト
FileDictTestsFileDictが解放されるfileDidChange(modificationDate:)は更新日時が変わっていれば読み直し、前回と同じならスキップするwith(saveToUserDict:)で置き換えた辞書が読み直せて、読み直しても「ユーが変わらないUserDictTests.testReloadFileDictWhenFileChangedNSFileCoordinatorから書き換えると、`di されるwithで置き換えたあとは、新しい辞書だけが読み直される実機での確認