521 Stimmen

Laden/Herunterladen von Bildern von URL auf Swift

Ich möchte ein Bild aus einer URL in meiner Anwendung laden, also habe ich es zuerst mit Objective-C versucht und es hat funktioniert, aber mit Swift habe ich einen Kompilierungsfehler:

'imageWithData' ist nicht verfügbar: Verwenden Sie die Objektkonstruktion 'UIImage(data:)'

Meine Funktion:

@IBOutlet var imageView : UIImageView

override func viewDidLoad() {
    super.viewDidLoad()

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

    imageView.image = UIImage.imageWithData(data)// Fehler hier
}

In Objective-C:

- (void)viewDidLoad {
    [super viewDidLoad];

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

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

Kann mir bitte jemand erklären, warum imageWithData: nicht mit Swift funktioniert und wie ich das Problem lösen kann.

908voto

Leo Dabus Punkte 215103

Xcode 8 oder später • Swift 3 oder später

Synchron:

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

Asynchron:

Erstellen Sie eine Methode mit einem Abschluss-Handler, um die Bilddaten von Ihrer URL zu erhalten

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

Erstellen Sie eine Methode zum Herunterladen des Bildes (Start der Aufgabe)

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")
        // immer das UI aus dem Hauptthread aktualisieren
        DispatchQueue.main.async() { [weak self] in
            self?.imageView.image = UIImage(data: data)
        }
    }
}

Verwendung:

override func viewDidLoad() {
    super.viewDidLoad()
    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. Das Bild wird im Hintergrund weiter heruntergeladen und geladen, wenn der Download beendet ist.")
}

Erweiterung:

extension UIImageView {
    func downloaded(from url: URL, contentMode mode: ContentMode = .scaleAspectFit) {
        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: ContentMode = .scaleAspectFit) { 
        guard let url = URL(string: link) else { return }
        downloaded(from: url, contentMode: mode)
    }
}

Verwendung:

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

435voto

Lucas Eduardo Punkte 11297

(Swift 4 Update) Um die ursprüngliche Frage direkt zu beantworten, hier ist das Swift-Äquivalent des geposteten Objective-C-Schnipsels.

let url = URL(string: image.url)
let data = try? Data(contentsOf: url!) // Stellen Sie sicher, dass Ihr Bild unter dieser URL vorhanden ist, sonst unwrappen in einer if let-Überprüfung / try-catch
imageView.image = UIImage(data: data!)

HAFTUNGSAUSSCHLUSS:

Es ist wichtig zu beachten, dass die Methode Data(contentsOf:) den Inhalt der URL synchron im selben Thread herunterlädt, in dem der Code ausgeführt wird, also nicht dies im Hauptthread Ihrer Anwendung aufrufen.

Ein einfacher Weg, um denselben Code asynchron auszuführen, ohne die Benutzeroberfläche zu blockieren, ist die Verwendung von GCD:

let url = URL(string: image.url)

DispatchQueue.global().async {
    let data = try? Data(contentsOf: url!) // Stellen Sie sicher, dass Ihr Bild unter dieser URL vorhanden ist, sonst unwrappen in einer if let-Überprüfung / try-catch
    DispatchQueue.main.async {
        imageView.image = UIImage(data: data!)
    }
}

Abgesehen davon, dass in realen Anwendungen, wenn Sie die beste Benutzererfahrung haben möchten und mehrfache Downloads desselben Bildes vermeiden möchten, möchten Sie diese möglicherweise nicht nur herunterladen, sondern auch zwischenspeichern. Es gibt bereits einige Bibliotheken, die das sehr nahtlos machen, und sie sind alle sehr einfach zu bedienen. Ich persönlich empfehle Kingfisher:

import Kingfisher

let url = URL(string: "url_des_bildes")
// das lädt das Bild asynchron herunter, wenn es noch nicht zwischengespeichert ist
imageView.kf.setImage(with: url) 

Funktioniert auch mit SwiftUI:

var body: some View {
    KFImage(URL(string: "https://example.com/image.png")!)
}

Und das war's

69voto

skywinder Punkte 20873

Wenn Sie nur das Bild (asynchron!) laden möchten - fügen Sie einfach diese kleine Erweiterung Ihrem Swift-Code hinzu:

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

Und verwenden Sie es auf diese Weise:

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

53voto

Mark Moeykens Punkte 13708

Xcode 12Swift 5

Die Antwort von Leo Dabus ist großartig! Ich wollte nur eine All-in-One-Funktionslösung bereitstellen:

if 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 { /// auf dem Hauptthread ausführen
            self.imageView.image = UIImage(data: data)
        }
    }

    task.resume()
}

46voto

swiftBoy Punkte 34715

Swift 2.2 || Xcode 7.3

Ich habe Erstaunliche Ergebnisse!! mit der AlamofireImage Swift-Bibliothek erhalten

Es bietet mehrere Funktionen wie:

  • Asynchron herunterladen
  • Automatische Bereinigung des Bildcaches, wenn Speicherwarnungen für die App auftreten
  • URL-Caching von Bildern
  • Bildcaching
  • Doppelte Downloads vermeiden

und ist sehr einfach für Ihre App zu implementieren

Schritt.1 Installiere Pods


Alamofire 3.3.x

pod 'Alamofire'

AlamofireImage 2.4.x

pod 'AlamofireImage'

Schritt.2 importieren und verwenden

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)

das ist alles!! es kümmert sich um alles


Vielen Dank an Alamofire Jungs, um das Leben der iDeveloper einfacher zu machen ;)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X