Caricamento / download di immagini dall'URL su Swift


415

Vorrei caricare un'immagine da un URL nella mia applicazione, quindi ho provato prima con Objective-C e ha funzionato, tuttavia, con Swift, ho un errore di compilazione:

'imageWithData' non è disponibile: usa la costruzione dell'oggetto 'UIImage (data :)'

La mia funzione:

@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
}

In 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";
 }

Qualcuno può spiegarmi perché imageWithData:non funziona con Swift e come posso risolvere il problema.


3
Prova questoimageURL.image = UIImage(data: myDataVar)
aleclarson,

Perfetto ha funzionato! Grazie Tuttavia non so perché questo metodo funzioni nell'Obiettivo C e non in Swift ... Strano
QuentR

Quando hai problemi con una classe Cocoa, prova CMD + facendo clic sul nome della classe e dovresti essere in grado di vedere l'interfaccia Swift per la classe!
aleclarson,

3
if let url = NSURL (stringa: "imageurl") {if let data = NSData (contentsOfURL: url) {imageView.image = UIImage (data: data)}}
Hardik Bar

2
@Leo Dabus Questa domanda non è specifica per Swift 2. Smetti di aggiungere quel tag.
Mick MacCallum

Risposte:


771

Xcode 8 o successivo • Swift 3 o successivo

sincrono:

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

in modo asincrono:

Crea un metodo con un gestore di completamento per ottenere i dati dell'immagine dal tuo URL

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

Crea un metodo per scaricare l'immagine (avvia l'attività)

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

Uso:

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.")
}

Estensione :

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

Uso:

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

13
Solo una nota a margine qui, dovresti impostare un oggetto associato ad esso; Altrimenti potresti caricare le immagini una sopra l'altra. Ad esempio in un punto in UITableViewcui una cella mostra un'immagine e l'immagine viene aggiornata quando viene restituita la cella dequeued. Se il processo n. 1 impiega più tempo del processo n. 2, il processo n. 2 mostrerà la sua immagine e verrà successivamente aggiornato dal processo n. 1 anche se l'immagine non è più valida per l'utente.
Paul Peelen,

1
Questo mi ha risolto il mio problema. Quando provo a caricare l'immagine con l'URL nella vista tabella, la vista di scorrimento non risponde realmente quando si scorre verso l'alto o verso il basso. Ho usato l'estensione UIImageView e ho risolto il mio problema. Grazie.
JengGe Chao

1
@LeoDabus ok grazie. e grazie per aver risposto a tante domande su SO! sei come un professore di swift e iOS. :)
Crashalot,

2
@LeoDabus come mai hai usato dataTaskWithURL invece di downloadTaskWithURL?
Crashalot,

3
Il primo scarica in memoria il secondo in un file
Leo Dabus,

350

(Aggiornamento Swift 4) Per rispondere direttamente alla domanda originale, ecco il rapido equivalente dello snippet Objective-C pubblicato.

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!)

NOTA BENE:

È importante notare che il Data(contentsOf:)metodo scaricherà il contenuto dell'URL in modo sincrono nello stesso thread in cui viene eseguito il codice, quindi non invocarlo nel thread principale dell'applicazione.

Un modo semplice per eseguire lo stesso codice in modo asincrono, senza bloccare l'interfaccia utente, è utilizzare 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!)
    }
}

Detto questo, nelle applicazioni della vita reale, se si desidera avere la migliore esperienza utente ed evitare download multipli della stessa immagine, è possibile che sia necessario scaricarli non solo, ma memorizzati nella cache. Ci sono già parecchie librerie che lo fanno senza soluzione di continuità e sono tutte davvero facili da usare. Consiglio personalmente 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) 

E questo è tutto


12
"Facilmente" è soggettivo e i programmatori principianti non si aspettano questo comportamento indesiderato, ma copiano / incollano questo frammento così com'è. Forse puoi aggiornare la tua risposta?
Orlin Georgiev,

13
Non sono ancora d'accordo. Alcune risposte dovrebbero essere semplici, molte persone che vengono qui amano copiare e incollare piccoli frammenti di codice. Ho appena tradotto in Swift il codice obiettivo-C dalla domanda originale, tutto a parte questo è un bonus. E a proposito, c'è già una risposta in questa stessa domanda che fornisce questo tipo di informazioni bonus, che ha meno senso duplicare le informazioni.
Lucas Eduardo,

1
@User sostituisce semplicemente l' image.urlURL della stringa, hardcoded o no :)
Lucas Eduardo,

1
@IanWarburton Naturalmente puoi usare quello che vuoi :). 1) Questa risposta si basa sulla domanda originale, che utilizzava lo stesso approccio nell'obiettivo-C, quindi ho appena aiutato nella "traduzione" per accelerare. 2) Non ha senso rimuovere questo approccio e mettere il URLSession.dataTaskperché molte altre risposte qui già mostrano come farlo, è meglio mantenere aperte le diverse opzioni.
Lucas Eduardo,

2
Heyo, la struttura suggerita, martin pescatore, come indicato nella risposta farà tutto il sollevamento pesante. Grazie per il suggerimento!
Kilmazing

68

Se vuoi solo caricare l'immagine (in modo asincrono!) , Aggiungi questa piccola estensione al tuo codice rapido:

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

E usalo in questo modo:

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

1
Non si presenta, e penso perché c'è bisogno di GCD. Come posso aggiornare?
jo3birdtalk,

@ jo3birdtalk non è un problema di GCD. Controlla i tuoi attacchi con vista.
skywinder,

6
NSURLConnection è obsoleto su iOS 9 e così via. Usa NSURLSession intead.
Muhasturk,

2
sendAsynchronousRequest è obsoleto in iOS 9
Crashalot

Grazie skywinder, sto usando questo metodo per scaricare immagini dall'array. Voglio che quando l'utente preme il cancelpulsante interrompe il download. Hai idea di come posso farlo usando questo metodo? Devo aggiungere la funzionalità di annullamento.
ZAFAR007,

44

Rapido 2.2 || Xcode 7.3

Ho ottenuto risultati incredibili !! con la libreria rapida AlamofireImage

Offre molteplici funzionalità come:

  • Download asincrono
  • Spurgo automatico della cache delle immagini se si verificano avvisi di memoria per l'app
  • Memorizzazione nella cache dell'URL dell'immagine
  • Memorizzazione nella cache delle immagini
  • Evita download duplicati

e molto facile da implementare per la tua app

Step.1 Installa pod


Alamofire 3.3.x

pod 'Alamofire'

AlamofireImage 2.4.x

pod "AlamofireImage"

Step.2 importare e utilizzare

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)

questo è tutto!! si prenderà cura di tutto


Un grande grazie ai ragazzi di Alamofire , per aver reso facile la vita di iDevelopers;)


8
Swift 3: foregroundImage.af_setImage (withURL: downloadURL come URL)
thejuki,

28

Xcode 8Swift 3

La risposta di Leo Dabus è fantastica! Volevo solo fornire una soluzione con funzioni all-in-one:

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
Mark, probabilmente significava "asincrono" alla fine lì
Fattie,

16

Ho racchiuso il codice delle migliori risposte alla domanda in un'unica classe riutilizzabile che estende UIImageView, in modo da poter utilizzare direttamente UIImageViews di caricamento asincrono nello storyboard (o crearle dal codice).

Ecco la mia classe:

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

ed ecco come usarlo:

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

2
Abbiamo davvero bisogno di quegli inizi scavalcati? Gli init non sono ereditati comunque? Sembra che stiamo solo scavalcando qui solo per chiamare super su se stesso, il che mi sembra ridondante.
Ingegnere tecnico di New York

16

Swift 4 ::

Questo mostrerà il caricatore durante il caricamento dell'immagine. È possibile utilizzare NSCache che memorizza temporaneamente l'immagine

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

Uso: -

truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)

1
Funziona. Basta copiare attività Rimozione dell'indicatore anche in caso di errore.
djdance,

1
molto utile per il mio progetto.
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
Utente

Hai qualche possibilità di scrivere qualcosa di asincrono?
Jed Grant,

@JedGrant potresti usare dispatch_async per entrare in un altro thread e un callback
Matej

Ho dovuto scartare NSData con un "!" (nota! alla fine) per farlo funzionare in questo modo: var imageData: NSData = NSData (contentsOfURL: url, opzioni: NSDataReadingOptions.DataReadingMappedIfSafe, errore: & err)!
botbot,

13

FYI: per swift-2.0 Xcode7.0 beta2

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
NSURLConnection è obsoleto. Devi usare NSURLSession. È meglio quando si codifica con Swift 2.0 e Xcode 7
BilalReffas

11

rapido 3 con gestione degli errori

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

Con Estensione

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

Utilizzo estensione

myImageView. setCustomImage("url")

Con supporto cache

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: un semplice caricatore di immagini di piccole dimensioni (ad es. Miniature) che utilizza NSCache e funziona sempre sul thread principale:

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

}

Uso:

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

Perché usare singleton con struct? questo renderà la tua classe immutabile, il che può causare problemi con NSCache
XcodeNOOB

Grazie per averlo sottolineato, l'ho appena cambiato class.
fethica,

1
private let cache mi stava dando errore, quindi l'ho cambiato in statico e ha funzionato! Grazie
Hammad Tariq

7

Ti consigliamo di fare:

UIImage(data: data)

In Swift, hanno sostituito la maggior parte dei metodi di fabbrica dell'obiettivo C con costruttori regolari.

Vedere:

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


2
Tecnicamente mappato, non sostituito. Se crei il tuo metodo +(instancetype)[MyThing thingWithOtherThing:], lo chiameresti anche come MyThing(otherThing: ...)in Swift.
Brian Nickel

7

Swift 2 con handle di errore e intestazione della richiesta personalizzata

Aggiungi semplicemente l'estensione a 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()
        }
    }
}

E poi, usa il nuovo imageFromUrl(urlString: String)per scaricare l'immagine

Uso:

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

in Swift 3, continuo a ricevere questo errore. Qual è il problema ? In questa riga "" "URLSession.shared.dataTask (con: url) {" "" "" "" Impossibile richiamare 'dataTask' con un elenco di argomenti di tipo '(con: URL, (Data ?, URLResponse ?, Errore? ) -> Void) '
Aymen BRomdhane,

7

Swift 4

Questo metodo scaricherà un'immagine da un sito Web in modo asincrono e la memorizzerà nella cache:

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

In uso:

    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
    }

Come va la cache? E per quanto tempo?
Ramis,

Sembra essere memorizzato in modo permanente, il che è strano, è archiviato nella cartella Libreria> Cache. Usa print (NSHomeDirectory ()) per arrivare a questa posizione sul tuo computer quando eseguito sul simulatore.
Bobby,

5

Swift 2.0:

1)

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

O

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

2) Aggiungi questo metodo a VC o Estensione.

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

Utilizzo:

self.load_image(" url strig here")

sendAsynchronousRequest è obsoleto in iOS 9
Crashalot

5

Kingfisher è una delle migliori librerie per caricare immagini in URL.

URL di 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

Ecco il codice di lavoro per caricare / scaricare l'immagine dall'URL. NSCache automaticamente e visualizza l'immagine segnaposto prima del download e carica l'immagine reale (codice Swift 4).

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!
                        }
                    }
                }
            }
        }
    }
}

Usa così:

// 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
L'unico che ha funzionato con me. il mio problema era che stavo implementando il lettore musicale e volevo che l'immagine venisse caricata nella notifica quando anche il telefono era chiuso e il gestore prende il tipo di UIImage, quindi ho dovuto usare questo metodo.
JhonnyTawk,

4

Un metodo per ottenere l'immagine che è sicura e funziona con Swift 2.0 e 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)
}

Quindi chiameresti questo metodo in questo modo:

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.
        }
    }

Se stai aggiornando la vista con l'immagine, dovrai usarla dopo "if success {":

    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
    }

Il motivo per cui quest'ultima parte è necessaria se si utilizza l'immagine nell'interfaccia utente è perché le chiamate di rete richiedono tempo. Se provi ad aggiornare l'interfaccia utente usando l'immagine senza chiamare dispatch_async come sopra, il computer cercherà l'immagine mentre l'immagine è ancora in fase di recupero, scoprirà che non ci sono (ancora) immagini e passa come se non ci fosse immagine trovato. Inserendo il codice all'interno di una chiusura di completamento dispatch_async si dice al computer: "Vai, ottieni questa immagine e quando hai finito, quindi completa questo codice". In questo modo, avrai l'immagine quando viene chiamato il codice e le cose funzioneranno bene.


4

Se stai cercando un'implementazione molto molto semplice. (Questo ha funzionato per me in 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)

Ho implementato all'interno di una tabella con una cella personalizzata che ha solo un'immagine

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

    }

hai ragione, questo perché il download e la compressione stanno avvenendo sul thread principale. idealmente dovresti fare questi 2 passaggi in modo asincrono in un thread in background, potresti usare la coda globale dispatch_async
Naishta

Sì, utilizzando il thread in background possiamo ottimizzare la velocità di download e, se necessario, possiamo modificare la logica anziché utilizzare sdWebImage o altro framework.
Gourav Joshi,

2

Consiglio di utilizzare la libreria Kingfisher per scaricare le immagini in modo asincrono. La parte migliore dell'utilizzo di Kingfisher è la memorizzazione nella cache di tutte le immagini scaricate per impostazione predefinita con l'URL dell'immagine come ID. La prossima volta che richiedi di scaricare l'immagine con quel particolare URl, la caricherà dalla cache.

Uso:

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

Puoi usare pod SDWebImageper ottenere lo stesso. È facile da usare Puoi ottenere documentaion qui SDWebImage

Ecco il codice di esempio

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

veloce 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
                    }
                }
            }
        }
    }
}

per usare

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

1

L'unica cosa che manca è un!

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!)

Ci scusiamo per la risposta tardiva, potresti essere più preciso su quali errori ricevi?
Simon Jensen,

1

Risposta rapida 2.x che scarica l'immagine in un file (al contrario della risposta di Leo Dabus, che memorizza l'immagine in memoria). Basato sulla risposta di Leo Dabus e sulla risposta di Rob da Ottieni i dati da NSURLSession DownloadTaskWithRequest dal gestore di completamento :

    // 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 Ho creato una funzione per passare l'URL dell'immagine, il tasto cache dopo che l'immagine è stata generata la imposta sul blocco di completamento.

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

Ho creato una semplice funzione di classe nella mia Utils.swiftclasse per chiamare quel metodo a cui puoi semplicemente accedere classname.methodnamee le tue immagini vengono salvate in NSCache usando la ImageCaching.swiftclasse

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

Happy Codding. Saluti:)


1

Swift 4.2 e AlamofireImage

Se l'utilizzo di una libreria non è un problema, puoi farlo con l'aiuto di AlamofireImage. i miei campioni provengono dal suo Github

Esempio di immagini segnaposto:

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)

ha molte utili funzioni ed estensioni per lavorare con le immagini. dalla memorizzazione nella cache al ridimensionamento e al ridimensionamento o persino all'applicazione di filtri sull'immagine. se le immagini sono importanti nella tua app, ti suggerisco di utilizzare questo framework e risparmiare tempo.


0

Utilizzando Ascyimageview puoi caricare facilmente imageurl in imageview.

let image1Url: URL = URL (string: "(imageurl)" come String)! imageview.imageURL = image1Url


0

Caricamento dell'immagine dal server: -

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

Utilizzo: -

  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

Per prestazioni migliori UITableViewo UICollectionViewutilizzare una libreria leggera Caricamento intelligente lento È possibile utilizzare questo approccio di caricamento lento se si desidera caricare immagini dall'URL asincrono

Smart 'Lazy Loading' in UICollectionViewo UITableViewusando NSOperatione NSOperationQueuein iOS Quindi in questo progetto possiamo scaricare più immagini in qualsiasi Vista ( UICollectionViewo UITableView) ottimizzando le prestazioni di un'app usando Operatione OperationQueueper la concorrenza. Di seguito sono riportati i punti chiave di questo progetto Smart Lazy Loading: Creazione del servizio di download delle immagini. Dai la priorità al download in base alla visibilità delle celle.

La classe ImageDownloadService creerà un'istanza singleton e avrà un'istanza NSCache per memorizzare nella cache le immagini che sono state scaricate. Abbiamo ereditato la classe Operation in TOperation per ridurre la funzionalità in base alle nostre esigenze. Penso che le proprietà della sottoclasse dell'operazione siano abbastanza chiare in termini di funzionalità. Stiamo monitorando i cambiamenti di stato delle operazioni utilizzando KVO.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.