Laden / Herunterladen von Bildern von der URL auf Swift


411

Ich möchte ein Bild von einer URL in meine Anwendung laden, also habe ich es zuerst mit Objective-C versucht und es hat funktioniert. Bei Swift habe ich jedoch 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://myURL/ios8.png")
    var data:NSData = NSData.dataWithContentsOfURL(url, options: nil, error: nil)

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

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

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


3
Versuchen Sie diesimageURL.image = UIImage(data: myDataVar)
Aleclarson

Perfekt, es hat funktioniert! Vielen Dank Ich weiß jedoch nicht, warum diese Methode in Ziel C und nicht in Swift
funktioniert

Wenn Sie Probleme mit einer Cocoa-Klasse haben, versuchen Sie CMD + Klicken Sie auf den Klassennamen und Sie sollten in der Lage sein, die Swift-Oberfläche für die Klasse zu sehen!
Aleclarson

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

2
@Leo Dabus Diese Frage ist nicht spezifisch für Swift 2. Bitte hören Sie auf, dieses Tag hinzuzufügen.
Mick MacCallum

Antworten:


769

Xcode 8 oder höher • Swift 3 oder höher

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 Completion-Handler, um die Bilddaten von Ihrer URL abzurufen

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 (starten Sie die 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")
        DispatchQueue.main.async() { [weak self] in
            self?.imageView.image = UIImage(data: data)
        }
    }
}

Verwendungszweck:

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

Erweiterung :

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

Verwendungszweck:

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

13
Nur eine Randnotiz hier, Sie sollten ein zugeordnetes Objekt darauf setzen; Andernfalls können Sie Bilder übereinander laden. ZB in einem Bereich, UITableViewin dem eine Zelle ein Bild zeigt und das Bild aktualisiert wird, wenn die aus der Warteschlange befindliche Zelle zurückgegeben wird. Wenn Prozess Nr. 1 länger dauert als Prozess Nr. 2, zeigt Prozess Nr. 2 sein Bild an und wird später von Prozess Nr. 1 aktualisiert, obwohl dieses Bild für den Benutzer nicht mehr gültig ist.
Paul Peelen

1
Das hat mich mein Problem gelöst. Wenn ich versuche, ein Bild mit einer URL in der Tabellenansicht zu laden, reagiert die Bildlaufansicht beim Scrollen nach oben oder unten nicht wirklich. Ich habe die UIImageView-Erweiterung verwendet und sie hat mein Problem gelöst. Vielen Dank.
JengGe Chao

1
@ LeoDabus ok danke. und danke, dass du so viele Fragen zu SO beantwortet hast! Du bist wie ein Professor für Swift und iOS. :)
Crashalot

2
@LeoDabus wie kommt es, dass Sie dataTaskWithURL anstelle von downloadTaskWithURL verwendet haben?
Crashalot

3
Der erste lädt in den Speicher der zweite in eine Datei
Leo Dabus

348

(Swift 4-Update) Um die ursprüngliche Frage direkt zu beantworten, finden Sie hier das schnelle Äquivalent des veröffentlichten Objective-C-Snippets.

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

HAFTUNGSAUSSCHLUSS:

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

Eine einfache Möglichkeit, 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!) //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!)
    }
}

Wenn Sie jedoch in realen Anwendungen die beste Benutzererfahrung erzielen und mehrere Downloads desselben Bildes vermeiden möchten, möchten Sie diese möglicherweise nicht nur herunterladen, sondern auch zwischenspeichern. Es gibt bereits einige Bibliotheken, die dies sehr nahtlos tun und die alle sehr einfach zu bedienen sind. Ich persönlich empfehle 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) 

Und das ist es


12
"Leicht" ist subjektiv, und unerfahrene Programmierer erwarten dieses unerwünschte Verhalten nicht, kopieren / fügen es jedoch so ein, wie es ist. Vielleicht können Sie Ihre Antwort aktualisieren?
Orlin Georgiev

13
Ich stimme immer noch nicht zu. Einige Antworten sollten einfach gehalten werden. Viele Leute, die hierher kommen, kopieren und fügen gerne kleine Codeausschnitte ein. Ich habe gerade den Ziel-C-Code aus der ursprünglichen Frage in Swift übersetzt, alles andere ist ein Bonus. Übrigens gibt es in derselben Frage bereits eine Antwort, die diese Art von Bonusinformationen liefert, was weniger sinnvoll ist, um Informationen zu duplizieren.
Lucas Eduardo

1
@ Benutzer ersetzen Sie einfach die image.urldurch eine Zeichenfolge URL, fest codiert oder nicht :)
Lucas Eduardo

1
@ IanWarburton Natürlich kannst du verwenden, was du willst :). 1) Diese Antwort basiert auf der ursprünglichen Frage, die den gleichen Ansatz in Ziel-C verwendete, also habe ich nur bei der "Übersetzung" geholfen, schnell zu sein. 2) Es ist nicht sinnvoll, diesen Ansatz zu entfernen und das zu setzen, URLSession.dataTaskda viele andere Antworten hier bereits zeigen, wie es geht. Es ist besser, die verschiedenen Optionen offen zu lassen.
Lucas Eduardo

2
Heyo, der vorgeschlagene Rahmen, Eisvogel, wie in der Antwort angegeben, wird das ganze schwere Heben erledigen. Danke für den Vorschlag!
Kilmazing

68

Wenn Sie nur ein Bild laden möchten (asynchron!), Fügen Sie einfach diese kleine Erweiterung zu Ihrem schnellen 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 benutze es so:

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

1
Es wird nicht angezeigt, und ich denke, weil GCD erforderlich ist. Wie aktualisiere ich?
Jo3birdtalk

@ jo3birdtalk es ist kein Problem von GCD. Überprüfen Sie Ihre Bindungen mit Blick.
Skywinder

6
NSURLConnection ist unter iOS 9 usw. veraltet. Verwenden Sie NSURLSession intead.
Muhasturk

2
sendAsynchronousRequest ist in iOS 9
Crashalot

Dank skywinder verwende ich diese Methode zum Herunterladen von Bildern aus dem Array. Ich möchte, wenn der Benutzer auf die cancelSchaltfläche drückt, wird der Download beendet. Haben Sie eine Idee, wie ich das mit dieser Methode machen kann? Ich muss die Abbruchfunktion hinzufügen.
ZAFAR007

44

Swift 2.2 ||Xcode 7.3

Ich habe erstaunliche Ergebnisse erzielt !! mit AlamofireImage schnelle Bibliothek

Es bietet mehrere Funktionen wie:

  • Asynchron herunterladen
  • Auto Curging Image Cache, wenn Speicherwarnungen für die App auftreten
  • Zwischenspeichern von Bild-URLs
  • Bild-Caching
  • Vermeiden Sie doppelte Downloads

und sehr einfach für Ihre App zu implementieren

Schritt 1 Pods installieren


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 es!! es wird sich um alles kümmern


Vielen Dank an Alamofire , die iDevelopers das Leben leichter gemacht haben;)


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

28

Xcode 8Swift 3

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

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, meinte dort wahrscheinlich "asynchron" am Ende
Fattie

16

Ich habe den Code der besten Antworten auf die Frage in eine einzige wiederverwendbare Klasse zusammengefasst, die UIImageView erweitert, sodass Sie das asynchrone Laden von UIImageViews direkt in Ihr Storyboard verwenden (oder sie aus Code erstellen) können.

Hier ist meine Klasse:

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

und hier ist, wie man es benutzt:

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

2
Brauchen wir wirklich diese überschriebenen Inits? Werden die Inits nicht trotzdem geerbt? Scheint, als würden wir hier nur überschreiben, um uns selbst super zu nennen, was mir überflüssig erscheint.
NYC Tech Engineer

16

Swift 4 ::

Dies zeigt den Lader beim Laden des Bildes. Sie können NSCache verwenden, der Bilder vorübergehend speichert

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

Verwendungszweck:-

truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)

1
Es klappt. Kopieren Sie einfach die Entfernung von activityIndicator im Fehlerfall.
DJDance

1
sehr nützlich für mein Projekt.
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
Benutzer

Gibt es eine Chance, dass Sie etwas Asynchrones schreiben können?
Jed Grant

@JedGrant Sie könnten dispatch_async verwenden, um in einen anderen Thread und einen Rückruf zu gelangen
Matej

Ich musste die NSData mit einem "!" (Beachten Sie das! am Ende), damit es so funktioniert: var imageData: NSData = NSData (contentOfURL: url, Optionen: NSDataReadingOptions.DataReadingMappedIfSafe, Fehler: & err)!
Botbot

13

Zu Ihrer Information: Für 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 ist entstellt. Sie müssen NSURLSession verwenden. Es ist besser, wenn Sie mit Swift 2.0 und Xcode 7
BilalReffas

10

schnelle 3 mit Fehlerbehandlung

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

Mit Erweiterung

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

Erweiterungsnutzung

myImageView. setCustomImage("url")

Mit Cache-Unterstützung

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: Ein einfacher Loader für kleine Bilder (z. B. Miniaturansichten), der NSCache verwendet und immer im Hauptthread ausgeführt wird:

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

}

Verwendungszweck:

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

Warum Singleton mit struct verwenden? Dies führt dazu, dass Ihre Klasse unveränderlich ist, was zu Problemen mit Ihrem NSCache führen kann
XcodeNOOB

Vielen Dank für den Hinweis, ich habe es gerade geändert class.
Fethica

1
Private Let Cache gab mir Fehler, also änderte es in statisch und es funktionierte! Danke
Hammad Tariq

7

Du wirst machen wollen:

UIImage(data: data)

In Swift haben sie die meisten Objective C-Factory-Methoden durch reguläre Konstruktoren ersetzt.

Sehen:

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


2
Technisch abgebildet, nicht ersetzt. Wenn Sie Ihre eigene Methode +(instancetype)[MyThing thingWithOtherThing:]erstellen, würden Sie sie auch wie MyThing(otherThing: ...)in Swift aufrufen .
Brian Nickel

7

Swift 2 mit Fehler Handle und benutzerdefiniertem Anforderungsheader

Fügen Sie einfach eine Erweiterung zu UIImageView hinzu:

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

Verwenden Sie dann das neue imageFromUrl(urlString: String), um das Bild herunterzuladen

Verwendungszweck:

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

In Swift 3 erhalte ich immer wieder diesen Fehler. Was ist das Problem ? In dieser Zeile "" "URLSession.shared.dataTask (with: url) {" "" "" "'dataTask' kann nicht mit einer Argumentliste vom Typ 'aufgerufen werden (mit: URL, (Data?, URLResponse?, Error? ) -> Void) '
Aymen BRomdhane

7

Swift 4

Diese Methode lädt ein Bild asynchron von einer Website herunter und speichert es zwischen:

    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 Benutzung:

    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
    }

Wie ist es Caching? Und für wie lange?
Ramis

Es scheint permanent gespeichert zu sein, was seltsam ist, es wird im Ordner Bibliothek> Caches gespeichert. Verwenden Sie print (NSHomeDirectory ()), um an diesen Speicherort auf Ihrem Computer zu gelangen, wenn Sie auf dem Simulator ausgeführt werden.
Bobby

5

Swift 2.0:

1)

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

ODER

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

2) Fügen Sie diese Methode zu VC oder Extension hinzu.

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

Verwendungszweck :

self.load_image(" url strig here")

sendAsynchronousRequest ist in iOS 9
Crashalot

5

Kingfisher ist eine der besten Bibliotheken zum Laden von Bildern in URLs.

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

Hier ist der Arbeitscode zum Laden / Herunterladen von Bildern von der URL. NSCache automatisch und Platzhalterbild vor dem Download anzeigen und aktuelles Bild laden (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!
                        }
                    }
                }
            }
        }
    }
}

Verwenden Sie wie folgt:

// 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
Das einzige was bei mir funktioniert hat. Mein Problem war, dass ich einen Musik-Player implementierte und wollte, dass das Bild in die Benachrichtigung geladen wird, wenn das Telefon ebenfalls geschlossen ist und der Handler den Typ UIImage verwendet, sodass ich diese Methode verwenden musste.
JhonnyTawk

4

Eine Methode, um das Bild zu erhalten, das sicher ist und mit Swift 2.0 und X-Code 7.1 funktioniert:

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

Sie würden diese Methode dann folgendermaßen aufrufen:

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

Wenn Sie die Ansicht mit dem Bild aktualisieren, müssen Sie dies nach dem "if success {" verwenden:

    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
    }

Der Grund, warum dieser letzte Teil benötigt wird, wenn Sie das Bild in der Benutzeroberfläche verwenden, liegt darin, dass Netzwerkanrufe einige Zeit in Anspruch nehmen. Wenn Sie versuchen, die Benutzeroberfläche mithilfe des Bildes zu aktualisieren, ohne dispatch_async wie oben aufzurufen, sucht der Computer nach dem Bild, während das Bild noch abgerufen wird, stellt fest, dass (noch) kein Bild vorhanden ist, und fährt fort, als ob kein Bild vorhanden wäre gefunden. Wenn Sie Ihren Code in einen Abschluss von dispatch_async einfügen, wird dem Computer mitgeteilt: "Gehen Sie, holen Sie sich dieses Bild, und wenn Sie fertig sind, vervollständigen Sie diesen Code." Auf diese Weise erhalten Sie das Bild, wenn der Code aufgerufen wird, und die Dinge funktionieren gut.


4

Wenn Sie nach einer sehr sehr einfachen Implementierung suchen. (Das hat bei mir in Swift 2 funktioniert)

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

Ich habe in einer Tabellenansicht eine benutzerdefinierte Zelle implementiert, die nur ein Bild enthält

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

    }

Sie haben Recht, das liegt daran, dass das Herunterladen und Komprimieren im Haupt-Thread stattfindet.
Idealerweise

Ja, mithilfe des Hintergrundthreads können wir die Downloadgeschwindigkeit optimieren und bei Bedarf die Logik ändern. Stattdessen können wir sdWebImage oder ein anderes Framework verwenden.
Gourav Joshi

2

Ich empfehle die Verwendung der Kingfisher-Bibliothek, um Bilder asynchron herunterzuladen. Das Beste an der Verwendung von Kingfisher ist, dass alle heruntergeladenen Bilder standardmäßig mit der Bild-URL als ID zwischengespeichert werden. Wenn Sie das nächste Mal das Herunterladen eines Bildes mit dieser bestimmten URl anfordern, wird es aus dem Cache geladen.

Verwendungszweck:

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

Sie können pod verwenden SDWebImage, um das gleiche zu erreichen. Es ist einfach zu bedienen. Hier können Sie SDWebImage dokumentieren

Hier ist der Beispielcode

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

1

Das einzige, was dort fehlt, ist ein!

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

Entschuldigen Sie die späte Antwort. Können Sie genauer sagen, welche Fehler Sie erhalten?
Simon Jensen

1

Schnelle 2.x-Antwort, die das Bild in eine Datei herunterlädt (im Gegensatz zu Leo Dabus 'Antwort, bei der das Bild im Speicher gespeichert wird). Basierend auf der Antwort von Leo Dabus und Robs Antwort von Holen Sie sich die Daten von NSURLSession DownloadTaskWithRequest vom Completion Handler :

    // 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 Ich habe eine Funktion erstellt, die nur die Bild-URL übergibt und den Cache-Schlüssel nach der Bildgenerierung auf den Abschlussblock setzt.

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

Ich habe in meiner Utils.swiftKlasse eine einfache Klassenfunktion zum Aufrufen dieser Methode erstellt, auf die Sie einfach zugreifen können, classname.methodnameund Ihre Bilder werden mithilfe der ImageCaching.swiftKlasse in NSCache gespeichert

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

Glückliches Codding. Prost:)


1

Swift 4.2 und AlamofireImage

Wenn die Verwendung einer Bibliothek kein Problem darstellt, können Sie dies mithilfe der AlamofireImage. Meine Proben stammen von seinem Github

Platzhalterbilder Beispiel:

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)

Es hat viele praktische Funktionen und Erweiterungen, um mit Bildern zu arbeiten. vom Caching über das Skalieren und Ändern der Größe bis hin zum Anwenden von Filtern auf das Bild. Wenn Bilder in Ihrer App wichtig sind, empfehle ich, dieses Framework zu verwenden und Zeit zu sparen.


1

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

zum Benutzen

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

0

Mit Ascyimageview können Sie imageurl einfach in imageview laden.

lass image1Url: URL = URL (string: "(imageurl)" als String)! imageview.imageURL = image1Url


0

Laden von Bildern vom 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()
}

Verwendungszweck :-

  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

Für eine bessere Leistung in UITableViewoder UICollectionViewVerwendung einer leichten Bibliothek Smart Lazy Loading Sie können diesen Lazy Loading-Ansatz verwenden, wenn Sie Bilder von der asynchronen URL laden möchten

Intelligentes 'Lazy Loading' in UICollectionViewoder UITableViewmit NSOperationund NSOperationQueueunter iOS In diesem Projekt können wir also mehrere Bilder in jeder Ansicht ( UICollectionViewoder UITableView) herunterladen, indem wir die Leistung einer App mithilfe von Operationund OperationQueuefür die gleichzeitige Verwendung optimieren . Im Folgenden sind die wichtigsten Punkte dieses Projekts aufgeführt: Smart Lazy Loading: Erstellen eines Bilddownload-Dienstes. Priorisieren Sie das Herunterladen anhand der Sichtbarkeit der Zellen.

Die ImageDownloadService-Klasse erstellt eine Singleton-Instanz und verfügt über eine NSCache- Instanz, um die heruntergeladenen Bilder zwischenzuspeichern. Wir haben die Operation-Klasse an TOperation geerbt, um die Funktionalität gemäß unseren Anforderungen zu ändern. Ich denke, die Eigenschaften der Operations-Unterklasse sind in Bezug auf die Funktionalität ziemlich klar. Wir überwachen Betriebszustandsänderungen mithilfe von KVO.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.