При прикреплении миниатюр к уведомлениям куда девается файл?

Я добавляю миниатюру в расширенное уведомление. Я создаю изображение для использования в качестве вложения следующим образом:

let url = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let fileURL = url.appendingPathComponent("someImageName", isDirectory: false).appendingPathExtension("png")
do{
    try UIImagePNGRepresentation(image)?.write(to: fileURL)
}catch{
    print("Could not write: ", error)
}

Это успешно. Если я сейчас запущу этот код:

let content = try? FileManager.default.contentsOfDirectory(atPath: NSTemporaryDirectory())
print(content ?? "error")

он печатает это: ["someImageName.png"].

Затем я создаю вложение, например:

let attachment = try? UNNotificationAttachment(identifier: "image", url: url, options: nil)
let content = UNMutableNotificationContent()
content.title = "Test"
content.attachments = [attachment!]
let request = UNNotificationRequest(identifier: "someID", content:content, trigger: /*someTrigger*/)
UNUserNotificationCenter.current().add(request, withCompletionHandler:...)

Это все работает. Уведомление отправляется, и вложение прикрепляется. Но если я сейчас распечатаю содержимое моей временной папки, она пуста! Изображение, которое я сохранил ранее, было удалено из этой папки.

После долгих проб и ошибок я обнаружил, что изображение удаляется в тот самый момент, когда я добавляю уведомление. Почему мое уведомление удаляет мое изображение? Я не могу найти никакой документации по этому поводу!

Если я сделаю все вышеперечисленное, но закомментирую эту строку: //content.attachments = [attachment!], что означает, что мое сохраненное изображение не будет добавлено в качестве приложения к моему уведомлению, то мое изображение не будет удалено из временной папки!

Эти файлы очищаются после использования? Или мне нужно искать в другой папке после исчезновения уведомления и чистить их вручную? Я не хочу, чтобы мое приложение создавало сотни изображений, которые больше никогда не будут использоваться, без возможности их удаления.


person Sti    schedule 05.07.2017    source источник


Ответы (1)


Я сталкиваюсь с той же проблемой в эти дни, и ответ находится в документации, не очень легко увидеть на первый взгляд, но он есть:

О UNNotificationAttachment:

...После проверки вложенные файлы перемещаются в хранилище данных вложений, чтобы к ним могли получить доступ все соответствующие процессы.

О методе инициализации:

Когда вы планируете запрос уведомления, содержащий вложение, файл вложения перемещается в новое место для облегчения доступа соответствующими процессами. После перемещения единственный способ получить доступ к файлу — использовать методы объекта UNUserNotificationCenter.

Заметь:

Вложения, расположенные внутри пакета приложения, копируются, а не перемещаются.

Поэтому я решил:

Написал файл, как вы, И написал его копию в NSTemporaryDirectory(). Я использовал этот пример, чтобы легко создавать и удалять TempDirectory (Swift 4.0) (спасибо Оле Бегемман):

import Foundation

/// A wrapper around a temporary file in a temporary directory. The directory
/// has been especially created for the file, so it's safe to delete when you're
/// done working with the file.
///
/// Call `deleteDirectory` when you no longer need the file.
struct TemporaryFile {
    let directoryURL: URL
    let fileURL: URL
    /// Deletes the temporary directory and all files in it.
    let deleteDirectory: () throws -> Void
    
    /// Creates a temporary directory with a unique name and initializes the
    /// receiver with a `fileURL` representing a file named `filename` in that
    /// directory.
    ///
    /// - Note: This doesn't create the file!
    init(creatingTempDirectoryForFilename filename: String) throws {
        let (directory, deleteDirectory) = try FileManager.default
            .urlForUniqueTemporaryDirectory()
        self.directoryURL = directory
        self.fileURL = directory.appendingPathComponent(filename)
        self.deleteDirectory = deleteDirectory
    }
}

extension FileManager {
    /// Creates a temporary directory with a unique name and returns its URL.
    ///
    /// - Returns: A tuple of the directory's URL and a delete function.
    ///   Call the function to delete the directory after you're done with it.
    ///
    /// - Note: You should not rely on the existence of the temporary directory
    ///   after the app is exited.
    func urlForUniqueTemporaryDirectory(preferredName: String? = nil) throws
        -> (url: URL, deleteDirectory: () throws -> Void)
    {
        let basename = preferredName ?? UUID().uuidString
        
        var counter = 0
        var createdSubdirectory: URL? = nil
        repeat {
            do {
                let subdirName = counter == 0 ? basename : "\(basename)-\(counter)"
                let subdirectory = temporaryDirectory
                    .appendingPathComponent(subdirName, isDirectory: true)
                try createDirectory(at: subdirectory, withIntermediateDirectories: false)
                createdSubdirectory = subdirectory
            } catch CocoaError.fileWriteFileExists {
                // Catch file exists error and try again with another name.
                // Other errors propagate to the caller.
                counter += 1
            }
        } while createdSubdirectory == nil
        
        let directory = createdSubdirectory!
        let deleteDirectory: () throws -> Void = {
            try self.removeItem(at: directory)
        }
        return (directory, deleteDirectory)
    }
}

После прикрепления файла с TempURL файл перемещается, и вы можете удалить TempDirectory.

Несколько тестов позже, и, чтобы быть уверенным, я наконец обнаружил, что мой файл (изображение в моем случае) хранится здесь:

URL: file:///var/mobile/Library/SpringBoard/PushStore/Attachments/com.YourApp.Name/8e52c6673f6e735f83535486bf750ba1118a3ade.png

После предъявления или очистки центра уведомлений файл удаляется да.

Почему все это ? -› Песочница! Когда я прикрепил свой файл к триггеру (здесь для меня UNCalendarNotificationTrigger), я назвал Календарь, ответственный за мой файл, чтобы представить его в моем уведомлении, но для его обработки он должен иметь файл в ЕГО каталоге.

Надеюсь, это поможет, мне потребовалось время, чтобы найти всю эту тайну!

person Mehdi Chennoufi    schedule 25.06.2018
comment
Просто чтобы убедиться, что я правильно понимаю, вы делаете акцент на следующем: После проверки вложенные файлы перемещаются в хранилище данных вложений, чтобы к ним могли получить доступ все соответствующие процессы, верно? В основном, что уведомление перемещается. Остальная часть цитаты вас не волнует: вложения, расположенные внутри пакета приложения, копируются, а не перемещаются, верно? - person Honey; 25.07.2020
comment
Верно, потому что в моем случае вложение — это изображение, сделанное пользователем, а не хранилище файлов в моем Bundle. Я отредактировал свой ответ. - person Mehdi Chennoufi; 25.07.2020
comment
Итак, мы должны удалить папку Temp, в которой мы решили сохранить изображение уведомления, или мы можем забыть об этом, потому что система сделает очистку за нас, как только уведомление будет запущено? - person Citizen_5; 14.04.2021
comment
@Citizen_5 Да, удалите его, когда закончите. Согласно Apple: хотя эти файлы не резервируются в iCloud, не забудьте удалить эти файлы, когда вы закончите с ними, чтобы они не продолжали занимать место на устройстве пользователя. Источник: developer.apple.com/icloud/documentation/data-storage - person Mehdi Chennoufi; 04.05.2021