Memuat / Mengunduh gambar dari URL di Swift

415

Saya ingin memuat gambar dari URL di aplikasi saya, jadi saya pertama kali mencoba dengan Objective-C dan itu berhasil, namun, dengan Swift, saya memiliki kesalahan kompilasi:

'imageWithData' tidak tersedia: gunakan konstruksi objek 'UIImage (data :)'

Fungsi saya:

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

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

Dapatkah seseorang tolong jelaskan saya mengapa imageWithData:itu tidak bekerja dengan Swift, dan bagaimana saya bisa menyelesaikan masalah.

QuentR
sumber
3
Coba iniimageURL.image = UIImage(data: myDataVar)
aleclarson
Sempurna itu berhasil! Terima kasih Namun saya tidak mengapa metode ini bekerja di Objective C, dan tidak di Swift ... Strange
QuentR
Ketika Anda memiliki masalah dengan kelas Cocoa, coba CMD + mengklik nama kelas dan Anda harus dapat melihat antarmuka Swift untuk kelas!
aleclarson
3
jika biarkan url = NSURL (string: "imageurl") {jika biarkan data = NSData (contentOfURL: url) {imageView.image = UIImage (data: data)}}
Hardik Bar
2
@ Leo Dabus Pertanyaan ini tidak spesifik untuk Swift 2. Tolong berhenti menambahkan tag itu ke sana.
Mick MacCallum

Jawaban:

770

Xcode 8 atau lebih baru • Swift 3 atau lebih baru

Serentak:

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

Secara serempak:

Buat metode dengan handler penyelesaian untuk mendapatkan data gambar dari url Anda

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

Buat metode untuk mengunduh gambar (memulai tugas)

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

Pemakaian:

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

Ekstensi :

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

Pemakaian:

imageView.downloaded(from: "https://cdn.arstechnica.net/wp-content/uploads/2018/06/macOS-Mojave-Dynamic-Wallpaper-transition.jpg")
Leo Dabus
sumber
13
Hanya catatan tambahan di sini, Anda harus mengatur objek terkait untuk itu; Kalau tidak, Anda dapat memuat gambar di atas satu sama lain. Misalnya di UITableViewmana sel menunjukkan gambar dan gambar diperbarui ketika sel yang dequeued dikembalikan. Jika proses # 1 membutuhkan waktu lebih lama dari proses # 2, proses # 2 akan menampilkan gambarnya dan kemudian akan diperbarui oleh proses # 1 meskipun gambar itu tidak lagi berlaku untuk pengguna.
Paul Peelen
1
Ini menyelesaikan masalah saya. Ketika saya mencoba memuat gambar dengan url dalam tampilan tabel, tampilan gulir benar-benar tidak merespons ketika gulir ke atas atau bawah. Saya menggunakan UIImageView Extension dan itu memecahkan masalah saya. Terima kasih.
JengGe Chao
1
@LeoDabus ok terima kasih. dan terima kasih telah menjawab begitu banyak pertanyaan di SO! Anda seperti seorang profesor swift dan iOS. :)
Crashalot
2
@LeoDabus kenapa Anda menggunakan dataTaskWithURL alih-alih mengunduhTaskWithURL?
Crashalot
3
Yang pertama mengunduh ke memori yang kedua ke file
Leo Dabus
350

(Pembaruan Swift 4) Untuk menjawab pertanyaan asli secara langsung, inilah persamaan cepat dari cuplikan Objective-C yang diposting.

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

PENOLAKAN:

Penting untuk dicatat bahwa Data(contentsOf:)metode ini akan mengunduh konten url secara serentak di utas yang sama dengan kode yang sedang dijalankan, jadi jangan gunakan ini di utas utama aplikasi Anda.

Cara mudah untuk membuat kode yang sama berjalan secara asinkron, tidak memblokir UI, adalah dengan menggunakan 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!)
    }
}

Yang mengatakan, dalam aplikasi kehidupan nyata, jika Anda ingin memiliki Pengalaman Pengguna terbaik dan menghindari beberapa unduhan dari gambar yang sama, Anda mungkin ingin memilikinya tidak hanya diunduh, tetapi juga di-cache. Sudah ada beberapa perpustakaan yang melakukan itu dengan sangat mulus dan semuanya sangat mudah digunakan. Saya pribadi merekomendasikan 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) 

Dan itu saja

Lucas Eduardo
sumber
12
"Mudah" adalah subyektif, dan coders pemula tidak akan mengharapkan perilaku yang tidak diinginkan ini, tetapi salin / tempel potongan ini apa adanya. Mungkin Anda dapat memperbarui jawaban Anda?
Orlin Georgiev
13
Saya masih tidak setuju. Beberapa jawaban harus dijaga tetap sederhana, banyak orang yang datang ke sini suka menyalin dan menempelkan potongan kecil kode. Saya baru saja menerjemahkan ke Swift kode objektif-C dari pertanyaan awal, semuanya selain itu adalah bonus. Dan omong-omong, sudah ada jawaban dalam pertanyaan yang sama memberikan informasi bonus semacam ini, yang kurang masuk akal untuk menggandakan informasi.
Lucas Eduardo
1
@ Pengguna hanya mengganti image.urldengan url string apa pun, hardcoded atau tidak :)
Lucas Eduardo
1
@ WangWarburton Tentu saja Anda dapat menggunakan apa pun yang Anda inginkan :). 1) Jawaban ini didasarkan pada pertanyaan awal, yang menggunakan pendekatan yang sama dalam tujuan-C, jadi saya hanya membantu dalam "terjemahan" menjadi cepat. 2) Tidak masuk akal untuk menghapus pendekatan ini dan meletakkannya URLSession.dataTaskkarena banyak jawaban lain di sini sudah menunjukkan bagaimana melakukannya, Lebih baik membiarkan berbagai opsi tetap terbuka.
Lucas Eduardo
2
Heyo, kerangka kerja yang disarankan, kingfisher, sebagaimana dinyatakan dalam jawaban akan melakukan semua pekerjaan berat. Terima kasih untuk sarannya!
Kilmazing
68

Jika Anda hanya ingin memuat gambar (Asinkron!) - cukup tambahkan ekstensi kecil ini ke kode cepat Anda:

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

Dan gunakan seperti ini:

myImageView.imageFromUrl("https://robohash.org/123.png")
pencukur langit
sumber
1
Itu tidak muncul, dan saya pikir karena ada kebutuhan untuk GCD. Bagaimana saya menyegarkan?
jo3birdtalk
@ jo3birdtalk itu bukan masalah GCD. Periksa ikatan Anda dengan tampilan.
Pencakar langit
6
NSURLConnection sudah usang di iOS 9 dan seterusnya. Gunakan NSURLSession intead.
muhasturk
2
sendAsynchronousRequest sudah tidak digunakan lagi di iOS 9
Crashalot
Terima kasih skywinder, saya menggunakan metode ini untuk mengunduh gambar dari array. Saya ingin ketika pengguna menekan canceltombol itu berhenti mengunduh. Apakah Anda tahu bagaimana saya bisa melakukan ini dengan menggunakan metode ini? Saya harus menambahkan fungsi pembatalan.
ZAFAR007
44

Swift 2.2 || Xcode 7.3

Saya mendapat hasil Luar Biasa !! dengan perpustakaan cepat AlamofireImage

Ini menyediakan beberapa fitur seperti:

  • Unduh asinkron
  • Auto Cache Gambar Cache jika peringatan memori terjadi untuk aplikasi
  • Caching URL gambar
  • Caching Gambar
  • Hindari Unduhan Gandakan

dan sangat mudah diimplementasikan untuk aplikasi Anda

Langkah.1 Instal pod


Alamofire 3.3.x

pod 'Alamofire'

Gambar Alamofire 2.4.x

pod 'AlamofireImage'

Langkah.2 impor dan Penggunaan

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)

itu dia!! itu akan mengurus semuanya


Terima kasih banyak kepada Alamofire guys , karena membuat hidup iDevelopers mudah;)

swiftBoy
sumber
8
Swift 3: foregroundImage.af_setImage (withURL: downloadURL as URL)
thejuki
28

Xcode 8Swift 3

Jawaban Leo Dabus luar biasa! Saya hanya ingin memberikan solusi fungsi 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()
Mark Moeykens
sumber
3
Mark, mungkin berarti "async" di akhir sana
Fattie
16

Saya membungkus kode jawaban terbaik untuk pertanyaan menjadi satu, kelas yang dapat digunakan kembali memperluas UIImageView, sehingga Anda dapat langsung menggunakan memuat asynchronous UIImageViews di storyboard Anda (atau membuatnya dari kode).

Ini kelas saya:

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

dan inilah cara menggunakannya:

imageView.downloadImage("http://www.image-server.com/myImage.jpg")
datayeah
sumber
2
Apakah kita benar-benar membutuhkan mereka yang ditimpa? Bukankah init itu warisan? Sepertinya kita hanya mengesampingkan di sini hanya untuk memanggil super sendiri, yang menurut saya berlebihan.
NYC Tech Engineer
16

Swift 4 ::

Ini akan menunjukkan pemuat saat memuat gambar. Anda dapat menggunakan NSCache yang menyimpan gambar sementara

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

Pemakaian:-

truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)
Mendongkrak
sumber
1
Berhasil. Cukup salin penghapusan activityIndicator dalam kasus kesalahan juga.
djdance
1
sangat berguna untuk proyek saya.
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)
pengguna3763002
sumber
5
fatal error: unexpectedly found nil while unwrapping an Optional value
Pengguna
Apakah Anda dapat menulis sesuatu yang tidak sinkron?
Jed Grant
@JedGrant Anda bisa menggunakan dispatch_async untuk masuk ke utas lainnya dan panggilan balik
Matej
Saya harus membuka NSData dengan "!" (catat! di akhir) untuk membuatnya berfungsi seperti ini: var imageData: NSData = NSData (contentOfURL: url, opsi: NSDataReadingOptions.DataReadingMappedIfSafe, error: & err)!
botbot
13

FYI: Untuk 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!)
            }
        }
    }
}
katopz
sumber
5
NSURLConnection rusak. Anda harus menggunakan NSURLSession. Lebih baik bila Anda kode dengan Swift 2.0 dan Xcode 7
BilalReffas
11

swift 3 dengan penanganan kesalahan

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

Dengan ekstensi

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

Penggunaan Ekstensi

myImageView. setCustomImage("url")

Dengan dukungan 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()
        }
    }
}
Manee ios
sumber
9

Swift 4: Pemuat sederhana untuk gambar kecil (mis: thumbnail) yang menggunakan NSCache dan selalu berjalan di utas utama:

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

}

Pemakaian:

ImageLoader.image(for: imageURL) { image in
  self.imageView.image = image
}
fethica
sumber
Mengapa menggunakan singleton dengan struct? ini akan menyebabkan kelas Anda menjadi tidak dapat diubah yang dapat menyebabkan masalah dengan NSCache Anda
XcodeNOOB
Terima kasih telah menunjukkan ini, saya baru saja mengubahnya class.
fethica
1
cache let pribadi memberi saya kesalahan sehingga mengubahnya menjadi statis dan berhasil! Terima kasih
Hammad Tariq
7

Anda ingin melakukannya:

UIImage(data: data)

Di Swift, mereka telah mengganti sebagian besar metode pabrik Objective C dengan konstruktor reguler.

Lihat:

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

Astaga
sumber
2
Dipetakan secara teknis, tidak diganti. Jika Anda membuat metode Anda sendiri +(instancetype)[MyThing thingWithOtherThing:], Anda akan menyebutnya seperti MyThing(otherThing: ...)di Swift juga.
Brian Nickel
7

Swift 2 dengan error Handle dan header permintaan khusus

Cukup tambahkan ekstensi ke 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()
        }
    }
}

Dan kemudian, gunakan yang baru imageFromUrl(urlString: String)untuk mengunduh gambar

Pemakaian:

imageView.imageFromUrl("https://i.imgur.com/ONaprQV.png")
Cody
sumber
di swift 3, saya terus mendapatkan kesalahan ini. Apa masalahnya ? Di baris ini "" "URLSession.shared.dataTask (with: url) {" "" "" "" Tidak dapat memanggil 'dataTask' dengan daftar argumen tipe '(dengan: URL, (Data ?, URLResponse ?, Kesalahan? ) -> Void) '
Aymen BRomdhane
7

Cepat 4

Metode ini akan mengunduh gambar dari situs web secara tidak sinkron dan menyimpannya:

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

Digunakan:

    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
    }
Polisi
sumber
Bagaimana cara caching? Dan untuk berapa lama?
Ramis
Tampaknya disimpan secara permanen, yang aneh, disimpan di folder Library> Caches. Gunakan cetak (NSHomeDirectory ()) untuk sampai ke lokasi ini di komputer Anda ketika dijalankan pada simulator.
Bobby
5

Swift 2.0:

1)

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

ATAU

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

2) Tambahkan metode ini ke VC atau Extension.

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

Penggunaan:

self.load_image(" url strig here")
AG
sumber
sendAsynchronousRequest sudah tidak digunakan lagi di iOS 9
Crashalot
5

Kingfisher adalah salah satu perpustakaan terbaik untuk memuat gambar ke 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)
Kamani Jasmin
sumber
5

Berikut adalah kode Bekerja untuk Memuat / Mengunduh gambar dari URL. NSCache secara otomatis dan Tampilkan gambar Placeholder sebelum mengunduh dan Muat gambar yang Sebenarnya (Kode 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!
                        }
                    }
                }
            }
        }
    }
}

Gunakan Seperti ini:

// 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 }
Nikunj Kumbhani
sumber
1
Satu-satunya yang bekerja dengan saya. masalah saya adalah saya mengimplementasikan pemutar musik dan saya ingin gambar untuk memuat pemberitahuan ketika telepon ditutup juga dan pawang mengambil jenis UIImage jadi saya harus menggunakan metode ini.
JhonnyTawk
4

Metode untuk mendapatkan gambar yang aman dan berfungsi dengan Swift 2.0 dan 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)
}

Anda kemudian akan memanggil metode ini seperti:

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

Jika Anda memperbarui tampilan dengan gambar, Anda harus menggunakannya setelah "jika berhasil {":

    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
    }

Alasan bagian terakhir ini diperlukan jika Anda menggunakan gambar di UI adalah karena panggilan jaringan membutuhkan waktu. Jika Anda mencoba memperbarui UI menggunakan gambar tanpa memanggil dispatch_async seperti di atas, komputer akan mencari gambar saat gambar masih diambil, temukan bahwa tidak ada gambar (belum), dan lanjutkan seolah-olah tidak ada gambar ditemukan. Menempatkan kode Anda di dalam penutupan penyelesaian dispatch_async mengatakan ke komputer, "Pergi, dapatkan gambar ini dan ketika Anda selesai, kemudian lengkapi kode ini." Dengan begitu, Anda akan memiliki gambar ketika kode dipanggil dan semuanya akan bekerja dengan baik.

Ben Patch
sumber
4

Jika Anda mencari implementasi yang sangat sangat sederhana. (Ini bekerja untuk saya di 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)

Saya menerapkan dalam tampilan tabel dengan sel khusus yang hanya memiliki gambar

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

    }
Naishta
sumber
Anda benar, itu karena mengunduh dan mengompresi terjadi pada utas utama. idealnya Anda harus melakukan 2 langkah ini secara asinkron dalam utas latar belakang, mungkin menggunakan antrian global dispatch_async
Naishta
Ya, dengan menggunakan utas latar belakang kami dapat mengoptimalkan kecepatan pengunduhan dan Jika diperlukan kami dapat mengubah logika alih-alih ini kami dapat menggunakan sdWebImage atau kerangka kerja lainnya.
Gourav Joshi
2

Saya sarankan menggunakan perpustakaan Kingfisher untuk mengunduh gambar secara tidak sinkron. Bagian terbaik tentang menggunakan Kingfisher adalah, cache semua gambar yang diunduh secara default dengan url gambar sebagai id. Lain kali ketika Anda meminta untuk mengunduh gambar dengan URl tertentu, itu akan memuatnya dari cache.

Pemakaian:

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()
                }
            })
Raj Salla
sumber
2

Anda dapat menggunakan pod SDWebImageuntuk mencapai hal yang sama. Mudah digunakan. Anda bisa mendapatkan dokumen di sini SDWebImage

Ini kode contohnya

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)
                }
            })
Shruti Thombre
sumber
2

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

untuk digunakan

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

Satu-satunya hal yang hilang adalah!

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!)
Simon Jensen
sumber
Maaf atas jawaban yang terlambat, bisakah Anda lebih teliti tentang kesalahan apa yang Anda dapatkan?
Simon Jensen
1

Jawaban Swift 2.x yang mengunduh gambar ke file (berbeda dengan jawaban Leo Dabus, yang menyimpan gambar dalam memori). Berdasarkan jawaban Leo Dabus dan jawaban Rob dari Dapatkan data dari NSURLSession DownloadTaskWithRequest dari complet 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

}
Crashalot
sumber
1

Swift 4.1 Saya telah membuat suatu fungsi cukup dengan url gambar, tombol cache setelah gambar dibuat setel ke blok penyelesaian.

   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()
      })
    }
  }
}
Gurjinder Singh
sumber
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()
        }
    }

Saya telah membuat fungsi kelas sederhana di Utils.swiftkelas saya untuk memanggil metode yang dapat Anda akses dengan mudah classname.methodnamedan gambar Anda disimpan di NSCache menggunakan ImageCaching.swiftkelas

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

Selamat Codding. Bersulang:)

Wisnu16
sumber
1

Swift 4.2 dan AlamofireImage

Jika menggunakan perpustakaan bukan masalah, Anda bisa melakukannya dengan bantuan AlamofireImage. sampel saya berasal dari Github -nya

Contoh Gambar Placeholder:

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)

ini memiliki banyak fungsi dan ekstensi yang berguna untuk bekerja dengan gambar. dari caching hingga scaling dan mengubah ukuran atau bahkan menerapkan filter pada gambar. jika gambar penting di aplikasi Anda, saya sarankan untuk menggunakan kerangka kerja ini dan menghemat waktu Anda.

Hamid Shahsavari
sumber
0

Penggunaan Ascyimageview Anda dapat dengan mudah memuat imageurl di imageview.

biarkan image1Url: URL = URL (string: "(imageurl)" sebagai String)! imageview.imageURL = image1Url

saurabh rathod
sumber
0

Memuat gambar dari 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()
}

Penggunaan: -

  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)
                        })
                    }
Abimanyu Rathore
sumber
0

Untuk kinerja yang lebih baik di UITableViewatau UICollectionViewgunakan pustaka ringan Pemuatan Malas Cerdas Anda dapat menggunakan pendekatan pemuatan malas ini jika Anda ingin memuat gambar dari url Asynchronous

Cerdas 'Lazy Loading' di UICollectionViewatau UITableViewmenggunakan NSOperationdan NSOperationQueuedi iOS Jadi dalam proyek ini kita dapat mengunduh banyak gambar di Tampilan apa pun ( UICollectionViewatau UITableView) dengan mengoptimalkan kinerja aplikasi dengan menggunakan Operationdan OperationQueueuntuk konkurensi. berikut ini adalah poin utama dari proyek ini. Pemuatan Malas Cerdas: Membuat Layanan unduhan gambar. Prioritaskan pengunduhan berdasarkan visibilitas sel.

Kelas ImageDownloadService akan membuat instance tunggal dan memiliki instance NSCache untuk cache gambar yang telah diunduh. Kami telah mewarisi kelas Operasi ke TOperation untuk menjalankan fungsi sesuai dengan kebutuhan kami. Saya pikir properti dari subclass operasi cukup jelas dalam hal fungsionalitas. Kami memantau perubahan operasi negara dengan menggunakan KVO.

jawadAli
sumber