Как вы закрываете открытые файлы, используя Swift?

Я загружаю ~1300 изображений. Это небольшие изображения, общий размер которых составляет около 500 КБ. Однако после загрузки и помещения их в userDefault я получаю сообщение об ошибке, как показано ниже:

libsystem_network.dylib: nw_route_get_ifindex:: socket (PF_ROUTE, SOCK_RAW, PF_ROUTE) не удалось: [24] Слишком много открытых файлов

Предполагается, что загруженные изображения PNG не закрываются.

Я уже расширил размер кеша с помощью ниже:

    // Configuring max network request cache size
    let memoryCapacity = 30 * 1024 * 1024 // 30MB
    let diskCapacity = 30 * 1024 * 1024   // 30MB
    let urlCache = URLCache(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "myDiscPath")
    URLCache.shared = urlCache

И вот подход, который я получил для хранения изображений:

    func storeImages (){
        for i in stride(from: 0, to: Cur.count, by: 1) {
            // Saving into userDefault
            saveIconsToDefault(row: i)
        }
    }

Я получаю сообщение об ошибке после того, как все они добавлены в userDefault. Итак, я знаю, что они там.

РЕДАКТИРОВАТЬ:

ФУНКЦИИ:

func getImageFromWeb(_ urlString: String, closure: @escaping (UIImage?) -> ()) {
    guard let url = URL(string: urlString) else {
        return closure(nil)
    }
    let task = URLSession(configuration: .default).dataTask(with: url) { (data, response, error) in
        guard error == nil else {
            print("error: \(String(describing: error))")
            return closure(nil)
        }
        guard response != nil else {
            print("no response")
            return closure(nil)
        }
        guard data != nil else {
            print("no data")
            return closure(nil)
        }
        DispatchQueue.main.async {
            closure(UIImage(data: data!))
        }
    }; task.resume()
}

func getIcon (id: String, completion: @escaping (UIImage) -> Void) {
    var icon = UIImage()

    let imageUrl = "https://files/static/img/\(id).png"

        getImageFromWeb(imageUrl) { (image) in
            if verifyUrl(urlString: imageUrl) == true {
                if let image = image {
                    icon = image
                    completion(icon)
                }
            } else {
                if let image = UIImage(named: "no_image_icon") {
                    icon = image
                    completion(icon)
                }
            }
        }
}

ИСПОЛЬЗОВАНИЕ:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "CurrencyCell", for: indexPath) as? CurrencyCell else { return UITableViewCell() }

    if currencies.count > 0 {
        let noVal = currencies[indexPath.row].rank ?? "N/A"
        let nameVal = currencies[indexPath.row].name ?? "N/A"
        let priceVal = currencies[indexPath.row].price_usd ?? "N/A"

        getIcon(id: currencies[indexPath.row].id!, completion: { (retImg) in
            cell.configureCell(no: noVal, name: nameVal, price: priceVal, img: retImg)
        })
    }
    return cell
}

1 ответ

Решение

URLSession(configuration: .default) Синтаксис создает новый URLSession за каждый запрос. Создать сингл URLSession (сохраняя его в каком-либо свойстве), а затем повторно используйте его для всех запросов. Или, если вы действительно не делаете никаких пользовательских настроек URLSessionПросто используйте URLSession.shared:

let task = URLSession.shared.dataTask(with: url) { data, response, error in
    ...
}
task.resume()

Вы упоминаете, что вы сохраняете 1300 изображений в UserDefaults, Это не подходящее место для хранения данных такого типа и для такого количества файлов. Я бы посоветовал вам использовать папку "Кэши", как описано в Руководстве по программированию файловой системы: В каталоге библиотеки хранятся файлы, специфичные для приложения.

let cacheURL = try! FileManager.default
    .url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    .appendingPathComponent("images")

// create your subdirectory before you try to save files into it
try? FileManager.default.createDirectory(at: cacheURL, withIntermediateDirectories: true)

Не поддавайтесь искушению хранить их в папке "Документы". Для получения дополнительной информации см. Рекомендации по хранению iOS.

Другие вопросы по тегам