Завантаження / завантаження зображення з URL-адреси на Swift


412

Я хотів би завантажити зображення з URL-адреси у своїй програмі, тому я спершу спробував з Objective-C, і це спрацювало, однак, зі Swift, у мене є помилка компіляції:

'imageWithData' недоступний: використовуйте конструкцію об'єкта 'UIImage (дані :)'

Моя функція:

@IBOutlet var imageView : UIImageView

override func viewDidLoad() {
    super.viewDidLoad()

    var url:NSURL = NSURL.URLWithString("http://myURL/ios8.png")
    var data:NSData = NSData.dataWithContentsOfURL(url, options: nil, error: nil)

    imageView.image = UIImage.imageWithData(data)// Error here
}

В Objective-C:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSURL *url = [NSURL URLWithString:(@"http://myURL/ios8.png")];
    NSData *data = [NSData dataWithContentsOfURL:url];

    _imageView.image = [UIImage imageWithData: data];
    _labelURL.text = @"http://www.quentinroussat.fr/assets/img/iOS%20icon's%20Style/ios8.png";
 }

Чи можете мені хтось пояснити, чому imageWithData:це не працює зі Свіфт, і як я можу вирішити проблему.


3
Спробуйте цеimageURL.image = UIImage(data: myDataVar)
aleclarson

Ідеально це працювало! Дякую, однак я не знаю, чому цей метод працює в цілі C, а не в Swift ... Дивно
QuentR

Якщо у вас виникли проблеми з класом какао, спробуйте CMD + клацання назви класу, і ви зможете побачити інтерфейс Swift для класу!
aleclarson

3
якщо нехай url = NSURL (рядок: "imageurl") {якщо нехай дані = NSData (contentOfURL: url) {imageView.image = UIImage (дані: дані)}}
Hardik Bar

2
@Leo Dabus Це питання не стосується Swift 2. Будь ласка, перестаньте додавати цей тег до нього.
Мік Маккаллум

Відповіді:


769

Xcode 8 або новіших версій • Swift 3 або новіших версій

Синхронно:

if let filePath = Bundle.main.path(forResource: "imageName", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath) {
    imageView.contentMode = .scaleAspectFit
    imageView.image = image
}

Асинхронно:

Створіть метод із обробником завершення, щоб отримати дані зображення зі свого URL-адреси

func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}

Створіть метод завантаження зображення (запустіть завдання)

func downloadImage(from url: URL) {
    print("Download Started")
    getData(from: url) { data, response, error in
        guard let data = data, error == nil else { return }
        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() { [weak self] in
            self?.imageView.image = UIImage(data: data)
        }
    }
}

Використання:

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    print("Begin of code")
    let url = URL(string: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")! 
    downloadImage(from: url)
    print("End of code. The image will continue downloading in the background and it will be loaded when it ends.")
}

Розширення :

extension UIImageView {
    func downloaded(from url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {  // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
        contentMode = mode
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil,
                let image = UIImage(data: data)
                else { return }
            DispatchQueue.main.async() { [weak self] in
                self?.image = image
            }
        }.resume()
    }
    func downloaded(from link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {  // for swift 4.2 syntax just use ===> mode: UIView.ContentMode
        guard let url = URL(string: link) else { return }
        downloaded(from: url, contentMode: mode)
    }
}

Використання:

imageView.downloaded(from: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")

13
Тут є лише бічна примітка, ви повинні встановити на неї пов’язаний об’єкт; Інакше ви можете завантажувати зображення один на одного. Наприклад, у UITableViewкомірці, де клітинка показує зображення, а зображення оновлюється при поверненні вилученої комірки. Якщо процес №1 займає більше часу, то процес №2 відобразить його зображення, а потім буде оновлено процесом №1, навіть якщо це зображення більше не дійсне для користувача.
Пол Пілін

1
Це вирішило мені свою проблему. Коли я намагаюся завантажити зображення з URL-адресою у поданні таблиці, подання прокрутки дійсно не відповідає, коли прокручується вгору або вниз. Я використовував розширення UIImageView, і це вирішило мою проблему. Дякую.
JengGe Chao

1
@LeoDabus ок, дякую. і дякую за відповідь на стільки питань на ТАК! ти як професор швидкої та iOS. :)
Crashalot

2
@LeoDabus, як ви використовували dataTaskWithURL замість downloadTaskWithURL?
Crashalot

3
Перший завантажує на пам'ять другий у файл
Лео Дабус

349

(Оновлення Swift 4) Щоб відповісти на початкове запитання безпосередньо, ось швидкий еквівалент розміщеного фрагмента Objective-C.

let url = URL(string: image.url)
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
imageView.image = UIImage(data: data!)

ВІДМОВА:

Важливо зауважити, що Data(contentsOf:)метод завантажуватиме вміст URL-адреси синхронно у тому ж потоці, що і виконується код, тому не посилайтеся на це в основний потік вашої програми.

Простий спосіб змусити асинхронно виконувати той самий код, не блокуючи інтерфейс користувача, за допомогою GCD:

let url = URL(string: image.url)

DispatchQueue.global().async {
    let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
    DispatchQueue.main.async {
        imageView.image = UIImage(data: data!)
    }
}

Це означає, що в додатках у реальному житті ви хочете мати найкращий досвід користувачів та уникати багаторазового завантаження одного і того ж зображення, ви можете також мати можливість їх не лише завантажувати, але й кешувати. Уже є досить багато бібліотек, що робить це дуже просто, і всі вони дуже зручні у використанні. Я особисто рекомендую Kingfisher :

import Kingfisher

let url = URL(string: "url_of_your_image")
// this downloads the image asynchronously if it's not cached yet
imageView.kf.setImage(with: url) 

І це все


12
"Легко" є суб'єктивним, і початківці кодери не очікують такої небажаної поведінки, але скопіюйте та вставте цей знімок таким, яким він є. Можливо, ви можете оновити свою відповідь?
Орлін Георгієв

13
Я все ще не згоден. Деякі відповіді мають бути простими, багато людей, які приходять сюди, люблять копіювати та вставляти невеликі фрагменти коду. Я щойно переклав на Swift об'єктивний-C код з оригінального питання, все, крім того, є бонусом. І, до речі, у цьому ж питанні вже є відповідь із наданням такого роду інформації про бонуси, що має менший сенс дублювати інформацію.
Лукас Едуардо

1
@User просто замініть image.urlбудь-яку URL-адресу рядка, жорстко кодовану чи ні :)
Лукас Едуардо

1
@IanWarburton Звичайно, ви можете використовувати все, що завгодно :). 1) Ця відповідь ґрунтується на оригінальному запитанні, яке використовувало той самий підхід у target-C, тому я просто допоміг у «перекладі» швидко. 2) Немає сенсу знімати цей підхід і ставити, URLSession.dataTaskоскільки багато інших відповідей тут уже показують, як це зробити, краще тримати різні варіанти відкритими.
Лукас Едуардо

2
Хейо, запропонований каркас, зимородок, як зазначено у відповіді, зробить все важке підняття. Дякую за пропозицію!
Кілмазінг

68

Якщо ви просто хочете завантажити зображення (асинхронно!) - просто додайте це невелике розширення до свого швидкого коду:

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSURLRequest(URL: url)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
                (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
                if let imageData = data as NSData? {
                    self.image = UIImage(data: imageData)
                }
            }
        }
    }
}

І використовуйте його таким чином:

myImageView.imageFromUrl("https://robohash.org/123.png")

1
Це не відображається, і я думаю, тому що є потреба в GCD. Як оновити?
jo3birdtalk

@ jo3birdtalk це не проблема GCD. Перевірте свої прив’язки з видом.
skywinder

6
Програма NSURLConnection застаріла на iOS 9 тощо. Використовуйте NSURLSession interad.
muhasturk

2
У iOS 9
Crashalot

Спасибі skywinder, я використовую цей метод для завантаження зображень з масиву. Я хочу, коли користувач натискає cancelкнопку, він перестає завантажувати. Чи маєте ви якесь уявлення, як я можу це зробити за допомогою цього методу? Мені потрібно додати функцію скасування.
ZAFAR007

44

Швидкий 2.2 || Xcode 7.3

Я отримав дивовижні результати !! з швидкою бібліотекою AlamofireImage

Він надає кілька функцій, таких як:

  • Асинхронно завантажуйте
  • Автоматична очищення кеш-пам'яті зображення, якщо для додатка трапляються попередження про пам’ять
  • Кешування URL-адрес зображення
  • Кешування зображень
  • Уникайте повторюваних завантажень

і дуже просто реалізувати для свого додатка

Крок.1 Встановіть стручки


Аламофір 3.3.x

pod "Alamofire"

AlamofireImage 2.4.x

під 'AlamofireImage'

Крок 2 імпорту та використання

import Alamofire
import AlamofireImage

let downloadURL = NSURL(string: "http://cdn.sstatic.net/Sites/stackoverflow/company/Img/photos/big/6.jpg?v=f4b7c5fee820")!
imageView.af_setImageWithURL(downloadURL)

Це воно!! це подбає про все


Велике спасибі хлопцям Alamofire , що полегшили життя iDevelopers;)


8
Swift 3: foregroundImage.af_setImage (зURL: завантажитиURL як URL)
thejuki

28

Xcode 8Swift 3

Відповідь Лео Дабуса приголомшлива! Я просто хотів запропонувати рішення функції "все в одному":

let url = URL(string: 
    "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png")

let task = URLSession.shared.dataTask(with: url!) { data, response, error in
    guard let data = data, error == nil else { return }

    DispatchQueue.main.async() {    // execute on main thread
        self.imageView.image = UIImage(data: data)
    }
}

task.resume()

3
Марк, ймовірно, означав "асинхронізацію" наприкінці
Fattie

16

Я загорнув код найкращих відповідей на питання в один, багаторазовий клас, що розширює UIImageView, тому ви можете безпосередньо використовувати асинхронне завантаження UIImageViews у вашій дошці розкадрування (або створити їх з коду).

Ось мій клас:

import Foundation
import UIKit

class UIImageViewAsync :UIImageView
{

    override init()
    {
        super.init(frame: CGRect())
    }

    override init(frame:CGRect)
    {
        super.init(frame:frame)
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func getDataFromUrl(url:String, completion: ((data: NSData?) -> Void)) {
        NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) { (data, response, error) in
            completion(data: NSData(data: data))
        }.resume()
    }

    func downloadImage(url:String){
        getDataFromUrl(url) { data in
            dispatch_async(dispatch_get_main_queue()) {
                self.contentMode = UIViewContentMode.ScaleAspectFill
                self.image = UIImage(data: data!)
            }
        }
    }
}

і ось як ним користуватися:

imageView.downloadImage("http://www.image-server.com/myImage.jpg")

2
Чи справді нам потрібні ті переоцінені уривки? Чи не спадкоємці все одно успадковані? Здається, що ми тут просто переосмислюємо лише те, щоб викликати супер на себе, що здається мені зайвим.
Технічний інженер NYC

16

Swift 4 :

Це покаже завантажувач під час завантаження зображення. Ви можете використовувати NSCache, який тимчасово зберігає зображення

let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
    func loadImageUsingCache(withUrl urlString : String) {
        let url = URL(string: urlString)
        if url == nil {return}
        self.image = nil

        // check cached image
        if let cachedImage = imageCache.object(forKey: urlString as NSString)  {
            self.image = cachedImage
            return
        }

        let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView.init(activityIndicatorStyle: .gray)
        addSubview(activityIndicator)
        activityIndicator.startAnimating()
        activityIndicator.center = self.center

        // if not, download image from url
        URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
            if error != nil {
                print(error!)
                return
            }

            DispatchQueue.main.async {
                if let image = UIImage(data: data!) {
                    imageCache.setObject(image, forKey: urlString as NSString)
                    self.image = image
                    activityIndicator.removeFromSuperview()
                }
            }

        }).resume()
    }
}

Використання: -

truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)

1
Це працює. Просто скопіюйте видалення ActivityIndicator і у випадку помилки.
djdance

1
дуже корисний для мого проекту.
partikles

13
let url = NSURL.URLWithString("http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg");
var err: NSError?
var imageData :NSData = NSData.dataWithContentsOfURL(url,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)
var bgImage = UIImage(data:imageData)

5
fatal error: unexpectedly found nil while unwrapping an Optional value
Користувач

Будь-який шанс ви можете написати щось асинхронне?
Джед Грант

@JedGrant, ви можете використовувати dispatch_async, щоб перейти в іншу нитку та зворотний виклик
Matej

Мені довелося розгортати NSData з "!" (зверніть увагу на! в кінці), щоб змусити його працювати так: var imageData: NSData = NSData (contentOfURL: url, параметри: NSDataReadingOptions.DataReadingMappedIfSafe, помилка: & помилка)!
ботбот

13

FYI: для бета-версії SWIFT-2.0 Xcode7.0

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSURLRequest(URL: url)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
            (response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
                self.image = UIImage(data: data!)
            }
        }
    }
}

5
NSURLCвключення знеструмлено. Ви повинні використовувати NSURLSession. Краще, коли ви
кодуєте

10

швидкий 3 з керуванням помилками

let url = URL(string: arr[indexPath.row] as! String)
if url != nil {
    DispatchQueue.global().async {
        let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
        DispatchQueue.main.async {
            if data != nil {
                cell.imgView.image = UIImage(data:data!)
            }else{
                cell.imgView.image = UIImage(named: "default.png")
            }
        }
    }
}

З розширенням

extension UIImageView {

    func setCustomImage(_ imgURLString: String?) {
        guard let imageURLString = imgURLString else {
            self.image = UIImage(named: "default.png")
            return
        }
        DispatchQueue.global().async { [weak self] in
            let data = try? Data(contentsOf: URL(string: imageURLString)!)
            DispatchQueue.main.async {
                self?.image = data != nil ? UIImage(data: data!) : UIImage(named: "default.png")
            }
        }
    }
}

Використання розширення

myImageView. setCustomImage("url")

Підтримка кешу

let imageCache = NSCache<NSString, UIImage>()

extension UIImageView {

    func loadImageUsingCacheWithURLString(_ URLString: String, placeHolder: UIImage?) {

        self.image = nil
        if let cachedImage = imageCache.object(forKey: NSString(string: URLString)) {
            self.image = cachedImage
            return
        }

        if let url = URL(string: URLString) {
            URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in

                //print("RESPONSE FROM API: \(response)")
                if error != nil {
                    print("ERROR LOADING IMAGES FROM URL: \(String(describing: error))")
                    DispatchQueue.main.async { [weak self] in
                        self?.image = placeHolder
                    }
                    return
                }
                DispatchQueue.main.async { [weak self] in
                    if let data = data {
                        if let downloadedImage = UIImage(data: data) {
                            imageCache.setObject(downloadedImage, forKey: NSString(string: URLString))
                            self?.image = downloadedImage
                        }
                    }
                }
            }).resume()
        }
    }
}

9

Swift 4: Простий завантажувач для невеликих зображень (наприклад, ескізи), який використовує NSCache і завжди працює на головній нитці:

class ImageLoader {

  private static let cache = NSCache<NSString, NSData>()

  class func image(for url: URL, completionHandler: @escaping(_ image: UIImage?) -> ()) {

    DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {

      if let data = self.cache.object(forKey: url.absoluteString as NSString) {
        DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
        return
      }

      guard let data = NSData(contentsOf: url) else {
        DispatchQueue.main.async { completionHandler(nil) }
        return
      }

      self.cache.setObject(data, forKey: url.absoluteString as NSString)
      DispatchQueue.main.async { completionHandler(UIImage(data: data as Data)) }
    }
  }

}

Використання:

ImageLoader.image(for: imageURL) { image in
  self.imageView.image = image
}

Навіщо використовувати синглтон з struct? це призведе до непорушності вашого класу, що може спричинити проблеми з вашим NSCache
XcodeNOOB

Дякую, що вказали на це, я щойно змінив це class.
fethica

1
приватний нехай кеш давав мені помилку, тому змінив його на статичний і він працював! Спасибі
Хаммад Тарік

7

Ви хочете зробити:

UIImage(data: data)

У Swift вони замінили більшість заводських методів Objective C звичайними конструкторами.

Подивитися:

https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-XID_26


2
Технічно нанесено на карту, не замінено. Якщо ви зробите свій власний метод +(instancetype)[MyThing thingWithOtherThing:], ви б назвали це як MyThing(otherThing: ...)у Swift.
Брайан Нікель

7

Swift 2 з ручкою помилок та користувацьким заголовком запиту

Просто додайте розширення до UIImageView:

extension UIImageView {
    public func imageFromUrl(urlString: String) {
        if let url = NSURL(string: urlString) {
            let request = NSMutableURLRequest(URL: url)
            request.setValue("<YOUR_HEADER_VALUE>", forHTTPHeaderField: "<YOUR_HEADER_KEY>")
            NSURLSession.sharedSession().dataTaskWithRequest(request) {
                (data, response, error) in
                guard let data = data where error == nil else{
                    NSLog("Image download error: \(error)")
                    return
                }

                if let httpResponse = response as? NSHTTPURLResponse{
                    if httpResponse.statusCode > 400 {
                        let errorMsg = NSString(data: data, encoding: NSUTF8StringEncoding)
                        NSLog("Image download error, statusCode: \(httpResponse.statusCode), error: \(errorMsg!)")
                        return
                    }
                }

            dispatch_async(dispatch_get_main_queue(), {
                NSLog("Image download success")
                self.image = UIImage(data: data)
            })
            }.resume()
        }
    }
}

А потім скористайтеся новим imageFromUrl(urlString: String)для завантаження зображення

Використання:

imageView.imageFromUrl("https://i.imgur.com/ONaprQV.png")

у швидкому 3, я продовжую отримувати цю помилку. В чому проблема ? У цьому рядку "" "URLSession.shared.dataTask (with: url) {" "" "" Неможливо викликати "dataTask" зі списком аргументів типу "(з: URL, (Data ?, URLResponse?, Помилка?" ) -> Пустота) '
Аймен Бромдхан

7

Швидкий 4

Цей метод завантажить зображення з веб-сайту асинхронно і кешує його:

    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()
    }

В вживанні:

    getImageFromWeb("http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") { (image) in
        if let image = image {
            let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
            imageView.image = image
            self.view.addSubview(imageView)
        } // if you use an Else statement, it will be in background
    }

Як це кешування? І на який термін?
Раміс

Здається, він постійно зберігається, що дивно, він зберігається в папці Бібліотека> Кеші. Використовуйте print (NSHomeDirectory ()), щоб дістатися до цього місця на своєму комп’ютері під час роботи на тренажері.
Боббі

5

Swift 2.0:

1)

if let url = NSURL(string: "http://etc...") {
    if let data = NSData(contentsOfURL: url) {
        imageURL.image = UIImage(data: data)
    }        
}

АБО

imageURL.image =
    NSURL(string: "http:// image name...")
    .flatMap { NSData(contentsOfURL: $0) }
    .flatMap { UIImage(data: $0) }

2) Додайте цей метод у VC або розширення.

func load_image(urlString:String)
{   let imgURL: NSURL = NSURL(string: urlString)!
    let request: NSURLRequest = NSURLRequest(URL: imgURL)

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (response: NSURLResponse?, data: NSData?, error: NSError?) in

        if error == nil {
            self.image_element.image = UIImage(data: data)
        }
    }
}

Використання:

self.load_image(" url strig here")

У iOS 9
Crashalot

5

Kingfisher - одна з найкращих бібліотек для завантаження зображення в URL.

URL-адреса Github - https://github.com/onevcat/Kingfisher

// If you want to use Activity Indicator.
imageview_pic.kf.indicatorType = .activity
imageview_pic.kf.setImage(with: URL(string: "Give your url string"))

// If you want to use custom placeholder image.
imageview_pic.kf.setImage(with: URL(string: "Give your url string"), placeholder: UIImage(named: "placeholder image name"), options: nil, progressBlock: nil, completionHandler: nil)

5

Ось робочий код для завантаження / завантаження зображення з URL-адреси. NSCache автоматично та відображає зображення заповнювача перед завантаженням та завантаженням фактичного зображення (Swift 4 Code).

func NKPlaceholderImage(image:UIImage?, imageView:UIImageView?,imgUrl:String,compate:@escaping (UIImage?) -> Void){

    if image != nil && imageView != nil {
        imageView!.image = image!
    }

    var urlcatch = imgUrl.replacingOccurrences(of: "/", with: "#")
    let documentpath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    urlcatch = documentpath + "/" + "\(urlcatch)"

    let image = UIImage(contentsOfFile:urlcatch)
    if image != nil && imageView != nil
    {
        imageView!.image = image!
        compate(image)

    }else{

        if let url = URL(string: imgUrl){

            DispatchQueue.global(qos: .background).async {
                () -> Void in
                let imgdata = NSData(contentsOf: url)
                DispatchQueue.main.async {
                    () -> Void in
                    imgdata?.write(toFile: urlcatch, atomically: true)
                    let image = UIImage(contentsOfFile:urlcatch)
                    compate(image)
                    if image != nil  {
                        if imageView != nil  {
                            imageView!.image = image!
                        }
                    }
                }
            }
        }
    }
}

Використовуйте так:

// Here imgPicture = your imageView
// UIImage(named: "placeholder") is Display image brfore download and load actual image. 

NKPlaceholderImage(image: UIImage(named: "placeholder"), imageView: imgPicture, imgUrl: "Put Here your server image Url Sting") { (image) in }

1
Єдине, що працювало зі мною. моя проблема полягала в тому, що я реалізовував музичний плеєр, і я хотів, щоб зображення завантажувалося в сповіщення, коли телефон також закритий, і обробник приймає тип UIImage, тому мені довелося використовувати цей метод.
JhonnyTawk

4

Спосіб отримання безпечного зображення та працює із Swift 2.0 та X-Code 7.1:

static func imageForImageURLString(imageURLString: String, completion: (image: UIImage?, success: Bool) -> Void) {
    guard let url = NSURL(string: imageURLString),
        let data = NSData(contentsOfURL: url),
        let image = UIImage(data: data)
        else { 
            completion(image: nil, success: false); 
            return 
       }

    completion(image: image, success: true)
}

Потім ви б назвали цей метод так:

imageForImageURLString(imageString) { (image, success) -> Void in
        if success {
            guard let image = image 
                 else { return } // Error handling here 
            // You now have the image. 
         } else {
            // Error handling here.
        }
    }

Якщо ви оновлюєте подання із зображенням, вам доведеться використовувати це після параметра "якщо успіх {":

    dispatch_async(dispatch_get_main_queue()) { () -> Void in
         guard let image = image 
              else { return } // Error handling here 
         // You now have the image. Use the image to update the view or anything UI related here
         // Reload the view, so the image appears
    }

Причина, що ця остання частина потрібна, якщо ви використовуєте зображення в інтерфейсі користувача, полягає в тому, що мережеві дзвінки потребують часу. Якщо ви спробуєте оновити користувальницький інтерфейс за допомогою зображення, не викликаючи dispatch_async, як вище, комп'ютер шукатиме зображення, поки зображення все ще видобувається, виявить, що зображення немає (поки що), і рухатиметься так, як ніби зображення не було знайдено. Поклавши свій код всередину закриття завершення dispatch_async, комп'ютер каже: "Ідіть, отримайте це зображення, і коли ви закінчите, тоді заповніть цей код". Таким чином, ви матимете зображення, коли буде викликаний код і все буде добре.


4

Якщо ви шукаєте дуже просту реалізацію. (Це працювало для мене у Swift 2)

 let imageURL = NSURL(string: "https://farm2.staticflickr.com/1591/26078338233_d1466b7da2_m.jpg")
 let imagedData = NSData(contentsOfURL: imageURL!)!
 imageView?.image = UIImage(data: imagedData)

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

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

        let cell = tableView.dequeueReusableCellWithIdentifier("theCell", forIndexPath: indexPath) as! customTableViewCell

        let imageURL = NSURL(string: "https://farm2.staticflickr.com/1591/26078338233_d1466b7da2_m.jpg")

        let imagedData = NSData(contentsOfURL: imageURL!)!

        cell.imageView?.image = UIImage(data: imagedData)

        return cell

    }

Ви маєте рацію, це тому, що завантаження та стискання відбувається в основній темі. в ідеалі вам слід виконати ці 2 кроки асинхронно у фоновій нитці, можливо, використовуйте глобальну чергу
dispatch_async

Так, за допомогою фонового потоку ми можемо оптимізувати швидкість завантаження, і якщо потрібно, ми можемо змінити логіку замість цього, ми можемо використовувати sdWebImage або інший фреймворк.
Гурав Джоші

2

Я рекомендую використовувати бібліотеку Kingfisher для завантаження зображень асинхронно. Найкраща частина використання Kingfisher - це кешування всіх завантажених зображень за замовчуванням із URL-адресом зображення як ідентифікатором. Наступного разу, коли ви запитаєте завантажити зображення саме з цим URl, він завантажить його з кеша.

Використання:

newsImage.kf.setImage(with: imageUrl!, placeholder: nil, options: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, imageUrl) in
                if error == nil{
                    self.activityIndicator.stopAnimating()
                }else if error != nil{
                    self.activityIndicator.stopAnimating()
                }
            })

2

SDWebImageДля досягнення того ж можна використовувати стручок . Його просто у використанні. Тут ви можете отримати документальний фільм SDWebImage

Ось зразок коду

self.yourImage.sd_setImage(with: NSURL(string: StrUrl as String ) as URL!, placeholderImage: placeholderImage, options: SDWebImageOptions(rawValue: 0), completed: { (image, error, cacheType, imageURL) in
                if( error != nil)
                {
                    print("Error while displaying image" , (error?.localizedDescription)! as String)
                }
            })

2

стрімкий 5

extension UIImageView {
    func load(url: URL) {
        DispatchQueue.global().async { [weak self] in
            if let data = try? Data(contentsOf: url) {
                if let image = UIImage(data: data) {
                    DispatchQueue.main.async {
                        self?.image = image
                    }
                }
            }
        }
    }
}

для використання

override func awakeFromNib() {
    super.awakeFromNib()
    imgView.load(url: "<imageURLHere>")
}

1

Єдине, чого там не вистачає - це!

let url = NSURL.URLWithString("http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg");
var err: NSError?
var imageData :NSData = NSData.dataWithContentsOfURL(url!,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)
var bgImage = UIImage(data:imageData!)

Вибачте за пізню відповідь, чи можете ви бути більш точними щодо помилок, які ви отримуєте?
Саймон Йенсен

1

Відповідь Swift 2.x, що завантажує зображення у файл (на відміну від відповіді Лео Дабуса, який зберігає зображення в пам'яті). На основі відповіді Лео Дабуса та відповіді Роба з Отримати дані з NSURLSession DownloadTaskWithRequest від обробника завершення :

    // Set download vars
    let downloadURL = NSURL() // URL to download from
    let localFilename = "foobar.png" // Filename for storing locally 

    // Create download request
    let task = NSURLSession.sharedSession().downloadTaskWithURL(downloadURL) { location, response, error in
        guard location != nil && error == nil else {
            print("Error downloading message: \(error)")
            return
        }

        // If here, no errors so save message to permanent location
        let fileManager = NSFileManager.defaultManager()
        do {
            let documents = try fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
            let fileURL = documents.URLByAppendingPathComponent(localFilename)
            try fileManager.moveItemAtURL(location!, toURL: fileURL)
            self.doFileDownloaded(fileURL, localFilename: localFilename)
            print("Downloaded message @ \(localFilename)")
        } catch {
            print("Error downloading message: \(error)")
        }
    }

    // Start download
    print("Starting download @ \(downloadURL)")
    task.resume()


// Helper function called after file successfully downloaded
private func doFileDownloaded(fileURL: NSURL, localFilename: String) {

    // Do stuff with downloaded image

}

1

Swift 4.1. Я створив функцію просто передати URL-адресу зображення, кеш-клавіша після генерування зображення встановлює її до блоку завершення.

   class NetworkManager: NSObject {

  private var imageQueue = OperationQueue()
  private var imageCache = NSCache<AnyObject, AnyObject>()

  func downloadImageWithUrl(imageUrl: String, cacheKey: String, completionBlock: @escaping (_ image: UIImage?)-> Void) {

    let downloadedImage = imageCache.object(forKey: cacheKey as AnyObject)
    if let  _ = downloadedImage as? UIImage {
      completionBlock(downloadedImage as? UIImage)
    } else {
      let blockOperation = BlockOperation()
      blockOperation.addExecutionBlock({
        let url = URL(string: imageUrl)
        do {
          let data = try Data(contentsOf: url!)
          let newImage = UIImage(data: data)
          if newImage != nil {
            self.imageCache.setObject(newImage!, forKey: cacheKey as AnyObject)
            self.runOnMainThread {
              completionBlock(newImage)
            }
          } else {
            completionBlock(nil)
          }
        } catch {
          completionBlock(nil)
        }
      })
      self.imageQueue.addOperation(blockOperation)
      blockOperation.completionBlock = {
        print("Image downloaded \(cacheKey)")
      }
    }
  }
}
extension NetworkManager {
  fileprivate func runOnMainThread(block:@escaping ()->Void) {
    if Thread.isMainThread {
      block()
    } else {
      let mainQueue = OperationQueue.main
      mainQueue.addOperation({
        block()
      })
    }
  }
}

1
class func downloadImageFromUrl(with urlStr: String, andCompletionHandler:@escaping (_ result:Bool) -> Void) {
        guard let url = URL(string: urlStr) else {
            andCompletionHandler(false)
            return
        }
        DispatchQueue.global(qos: .background).async {
            URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) -> Void in
                if error == nil {
                    let httpURLResponse = response as? HTTPURLResponse
                    Utils.print( "status code ID : \(String(describing: httpURLResponse?.statusCode))")
                    if httpURLResponse?.statusCode == 200 {
                        if let data = data {
                            if let image = UIImage(data: data) {
                                ImageCaching.sharedInterface().setImage(image, withID: url.absoluteString as NSString)
                                DispatchQueue.main.async {
                                    andCompletionHandler(true)
                                }
                            }else {
                                andCompletionHandler(false)
                            }
                        }else {
                            andCompletionHandler(false)
                        }
                    }else {
                        andCompletionHandler(false)
                    }
                }else {
                    andCompletionHandler(false)
                }
            }).resume()
        }
    }

Я створив у своєму Utils.swiftкласі просту функцію класу для виклику цього методу, до якого ви можете просто отримати доступ, classname.methodnameа ваші зображення зберігаються в NSCache за допомогою ImageCaching.swiftкласу

Utils.downloadImageFromUrl(with: URL, andCompletionHandler: { (isDownloaded) in
                            if isDownloaded {
                                if  let image = ImageCaching.sharedInterface().getImage(URL as NSString) {
                                    self.btnTeam.setBackgroundImage(image, for: .normal)
                                }
                            }else {
                                DispatchQueue.main.async {
                                    self.btnTeam.setBackgroundImage(#imageLiteral(resourceName: "com"), for: .normal)
                                }
                            }
                        })

Щасливі Кодінг. Ура :)


1

Swift 4.2 та AlamofireImage

Якщо використання бібліотеки не є проблемою, ви можете це зробити за допомогою AlamofireImage. мої зразки з його Github

Приклад зображень заповнювача:

let imageView = UIImageView(frame: frame)
let url = URL(string: "https://httpbin.org/image/png")!
let placeholderImage = UIImage(named: "placeholder")!
imageView.af_setImage(withURL: url, placeholderImage: placeholderImage)

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


0

Використовуючи Ascyimageview, ви можете легко завантажити imageurl у перегляді зображень.

нехай image1Url: URL = URL (рядок: "(imageurl)" як String)! imageview.imageURL = image1Url


0

Завантаження зображень із сервера: -

func downloadImage(from url: URL , success:@escaping((_ image:UIImage)->()),failure:@escaping ((_ msg:String)->())){
    print("Download Started")
    getData(from: url) { data, response, error in
        guard let data = data, error == nil else {
            failure("Image cant download from G+ or fb server")
            return
        }

        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() {
             if let _img = UIImage(data: data){
                  success(_img)
            }
        }
    }
}
func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url, completionHandler: completion).resume()
}

Використання: -

  if let url = URL(string: "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") {
                        self.downloadImage(from:url , success: { (image) in
                            print(image)

                        }, failure: { (failureReason) in
                            print(failureReason)
                        })
                    }

0

Для кращої продуктивності UITableViewабо UICollectionViewвикористання бібліотеки легкої ваги Smart Lazy Loading Ви можете використовувати цей підхід для ледачого завантаження, якщо ви хочете завантажити зображення з URL-адреси Асинхронний

Розумне "Ледаче завантаження" в UICollectionViewабо UITableViewза допомогою iOS NSOperationта NSOperationQueueiOS. У цьому проекті ми можемо завантажувати декілька зображень у будь-якому режимі перегляду ( UICollectionViewабо UITableView), оптимізуючи ефективність програми за допомогою Operationта OperationQueueза одночасність. нижче ключовий момент цього проекту Smart Lazy Loading: Створення служби завантаження зображень. Визначте пріоритет завантаження на основі видимості комірок.

Клас ImageDownloadService створить однотонний екземпляр і мати примірник NSCache для кешування завантажуваних зображень. Ми передали клас Operation на TOperation, щоб проаналізувати функціональність відповідно до наших потреб. Я думаю, що властивості підкласу операції досить чіткі з точки зору функціональності. Ми здійснюємо моніторинг змін операцій за допомогою КВО.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.