Repository navigation
删除消息时,一并删除不再被引用的图片缓存 #368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
删除消息时,一并删除不再被引用的图片缓存 #368
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| // | ||
| // MessageImageCleaner.swift | ||
| // Bark | ||
| // | ||
| // Created by Cnitor on 2026/8/26. | ||
| // Copyright © 2026 Cnitor. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
| import Kingfisher | ||
| import RealmSwift | ||
|
|
||
| /* | ||
| 消息记录里的 image 字段只保存图片地址,图片本体由 NotificationServiceExtension 下载后, | ||
| 存放在 App Groups 共享的 Kingfisher 图片缓存中(详见 ImageDownloader)。 | ||
| 存入时用的是 StorageExpiration.never,不会自动过期,所以消息删除后必须主动清理,否则图片文件会一直残留。 | ||
|
|
||
| 通知中心里推送显示的图不受影响,那是 NSE 复制出来的附件副本。 | ||
| 但下拉查看大图读的是同一份缓存,缓存删掉后会重新联网下载,离线时那条推送的大图就显示不出来了, | ||
| 这是删图片必然要付出的代价。 | ||
| */ | ||
| class MessageImageCleaner { | ||
| static let shared = MessageImageCleaner() | ||
|
|
||
| private let cleanQueue = DispatchQueue(label: "me.fin.bark.message-image-clean", qos: .utility) | ||
|
|
||
| /// 与 ImageDownloader 使用同一个图片缓存 | ||
| private lazy var imageCache: ImageCache? = { | ||
| guard let groupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.bark") else { | ||
| return nil | ||
| } | ||
| return try? ImageCache(name: "shared", cacheDirectoryURL: groupUrl) | ||
| }() | ||
|
|
||
| private init() {} | ||
|
|
||
| /// 收集这些消息引用的图片地址,需要在消息删除`之前`调用 | ||
| func imageUrls(in messages: Results<Message>) -> [String] { | ||
| return Array(Set(messages.filter("image != nil").compactMap { $0.image })) | ||
| } | ||
|
|
||
| /// 删除不再被任何消息引用的图片缓存,需要在消息删除`之后`调用 | ||
| /// - Parameter completion: 清理流程结束后回调,不代表全部删除成功。 | ||
| /// 无候选图片时立即调用,其余情况在后台队列调用。 | ||
| func removeUnreferencedImages(_ imageUrls: [String?], completion: (() -> Void)? = nil) { | ||
| let candidates = Set(imageUrls.compactMap { $0 }) | ||
| guard !candidates.isEmpty else { | ||
| completion?() | ||
| return | ||
| } | ||
|
|
||
| cleanQueue.async { | ||
| guard let cache = self.imageCache, let realm = try? Realm() else { | ||
| completion?() | ||
| return | ||
| } | ||
| // GCD 线程上的 Realm 不自动刷新,refresh 以避免读到旧快照 | ||
| realm.refresh() | ||
|
|
||
| // 按索引查询是否还被其它消息引用 | ||
| let messages = realm.objects(Message.self) | ||
| let group = DispatchGroup() | ||
| for imageUrl in candidates { | ||
| guard let url = URL(string: imageUrl) else { | ||
| continue | ||
| } | ||
| // 原始地址和百分号编码地址对应同一个缓存文件,二者皆查 | ||
| let aliases = Set([imageUrl, url.absoluteString, imageUrl.removingPercentEncoding].compactMap { $0 }) | ||
| guard messages.filter("image IN %@", aliases).isEmpty else { | ||
| continue | ||
| } | ||
| // 缓存 key 与 ImageDownloader 存入时保持一致 | ||
| group.enter() | ||
| cache.removeImage(forKey: url.cacheKey, fromMemory: true, fromDisk: true) { | ||
| group.leave() | ||
| } | ||
| } | ||
| // 等所有异步删除操作结束后再回调,不阻塞清理队列 | ||
| group.notify(queue: self.cleanQueue) { | ||
| completion?() | ||
| } | ||
| } | ||
| } | ||
| } | ||
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
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
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
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.
Uh oh!
There was an error while loading. Please reload this page.