Đang tải / tải hình ảnh từ URL trên Swift


414

Tôi muốn tải một hình ảnh từ một URL trong ứng dụng của mình, vì vậy lần đầu tiên tôi đã thử với Objective-C và nó đã hoạt động, tuy nhiên, với Swift, tôi đã gặp lỗi biên dịch:

'imageWithData' không khả dụng: sử dụng xây dựng đối tượng 'UIImage (dữ liệu :)'

Chức năng của tôi:

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

Trong Mục tiêu-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";
 }

Ai đó có thể vui lòng giải thích cho tôi tại sao điều imageWithData:đó không hoạt động với Swift không và làm cách nào để giải quyết vấn đề.


3
Hãy thử điều nàyimageURL.image = UIImage(data: myDataVar)
aleclarson

Hoàn hảo nó làm việc! Cảm ơn bạn Tuy nhiên tôi không hiểu tại sao phương pháp này hoạt động trong Mục tiêu C, chứ không phải trong Swift ... Lạ
QuentR

Khi bạn gặp sự cố với lớp Ca cao, hãy thử CMD + nhấp vào tên lớp và bạn sẽ có thể thấy giao diện Swift cho lớp!
aleclarson

3
if let url = NSURL (chuỗi: "imageurl") {if let data = NSData (nội dungOfURL: url) {imageView.image = UIImage (data: data)}}
Hardik Bar

2
@Leo Dabus Câu hỏi này không dành riêng cho Swift 2. Vui lòng dừng thêm thẻ đó vào nó.
Mick MacCallum

Câu trả lời:


769

Xcode 8 trở lên • Swift 3 trở lên

Đồng bộ:

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

Không đồng bộ:

Tạo một phương thức với trình xử lý hoàn thành để lấy dữ liệu hình ảnh từ url của bạn

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

Tạo một phương thức để tải xuống hình ảnh (bắt đầu nhiệm vụ)

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

Sử dụng:

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

Gia hạn :

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

Sử dụng:

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

13
Chỉ cần một lưu ý phụ ở đây, bạn nên đặt một đối tượng liên quan đến nó; Nếu không, bạn có thể tải hình ảnh lên nhau. Ví dụ, trong UITableViewđó một ô hiển thị một hình ảnh và hình ảnh được cập nhật khi ô bị khử được trả về. Nếu quy trình số 1 mất nhiều thời gian hơn thì quy trình số 2, quy trình số 2 sẽ hiển thị hình ảnh của nó và sau đó nó sẽ được cập nhật bởi quy trình số 1 ngay cả khi hình ảnh đó không còn hợp lệ cho người dùng.
Paul Peelen

1
Điều này giải quyết cho tôi vấn đề của tôi. Khi tôi cố tải hình ảnh bằng url trong chế độ xem bảng, chế độ xem cuộn thực sự không phản hồi khi cuộn lên trên hoặc xuống. Tôi đã sử dụng UIImageView Extension và nó đã giải quyết vấn đề của tôi. Cảm ơn.
JengGe Chao

1
@LeoDabus ok cảm ơn. và cảm ơn vì đã trả lời rất nhiều câu hỏi về SO! bạn giống như một giáo sư của swift và iOS. :)
Crashalot

2
@LeoDabus tại sao bạn lại sử dụng dataTaskWithURL thay vì downloadTaskWithURL?
Crashalot

3
Cái đầu tiên tải xuống bộ nhớ cái thứ hai vào một tập tin
Leo Dabus

350

(Cập nhật Swift 4) Để trả lời trực tiếp câu hỏi ban đầu, đây là phần tương đương nhanh chóng của đoạn trích Objective-C đã đăng.

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

TUYÊN BỐ TỪ CHỐI:

Điều quan trọng cần lưu ý là Data(contentsOf:)phương thức sẽ tải xuống nội dung của url một cách đồng bộ trong cùng một luồng mà mã đang được thực thi, vì vậy đừng gọi điều này trong luồng chính của ứng dụng của bạn.

Một cách dễ dàng để làm cho cùng một mã chạy không đồng bộ, không chặn UI, là sử dụng 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!)
    }
}

Điều đó nói rằng, trong các ứng dụng thực tế, nếu bạn muốn có Trải nghiệm người dùng tốt nhất và tránh nhiều lần tải xuống của cùng một hình ảnh, bạn cũng có thể muốn chúng không chỉ được tải xuống mà còn được lưu trong bộ nhớ cache. Đã có khá nhiều thư viện hoạt động rất liền mạch và tất cả chúng đều thực sự dễ sử dụng. Cá nhân tôi khuyên dùng 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) 

Và đó là nó


12
"Dễ dàng" là chủ quan, và các lập trình viên mới làm quen sẽ không mong đợi hành vi không mong muốn này, nhưng sao chép / dán đoạn trích này như hiện tại. Có lẽ bạn có thể cập nhật câu trả lời của bạn?
Orlin Georgiev

13
Tôi vẫn không đồng ý. Một số câu trả lời nên được giữ đơn giản, rất nhiều người đến đây thích sao chép và dán các đoạn mã nhỏ. Tôi vừa dịch sang Swift mã mục tiêu-C từ câu hỏi ban đầu, mọi thứ bên cạnh đó là phần thưởng. Và nhân tiện, đã có một câu trả lời trong cùng một câu hỏi cung cấp loại thông tin thưởng này, điều này ít có ý nghĩa đối với thông tin trùng lặp.
Lucas Eduardo

1
@ Người dùng chỉ cần thay thế image.urlbằng bất kỳ url chuỗi nào, có mã hóa cứng hay không :)
Lucas Eduardo

1
@IanWarburton Tất nhiên bạn có thể sử dụng bất cứ thứ gì bạn muốn :). 1) Câu trả lời này dựa trên câu hỏi ban đầu, sử dụng cùng một cách tiếp cận trong mục tiêu-C, vì vậy tôi chỉ giúp "dịch" để nhanh chóng. 2) Không có ý nghĩa gì khi loại bỏ phương pháp này và đưa ra URLSession.dataTaskbởi vì rất nhiều câu trả lời khác ở đây đã chỉ ra cách thực hiện, tốt hơn là giữ các tùy chọn khác nhau được mở.
Lucas Eduardo

2
Heyo, khung đề xuất, bói cá, như đã nêu trong câu trả lời sẽ làm tất cả những việc nặng nhọc. Cám ơn vì sự gợi ý!
Kilmazed

68

Nếu bạn chỉ muốn tải hình ảnh (Không đồng bộ!) - chỉ cần thêm tiện ích mở rộng nhỏ này vào mã nhanh chóng của bạn:

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

Và sử dụng nó theo cách này:

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

1
Nó không hiển thị, và tôi nghĩ bởi vì cần phải có GCD. Làm thế nào để tôi làm mới?
jo3birdtalk 7/2/2016

@ jo3birdtalk không phải là vấn đề của GCD. Kiểm tra các ràng buộc của bạn với xem.
skywinder 8/2/2016

6
NSURLConnection không được dùng nữa trên iOS 9, v.v. Sử dụng NSURLSession trong đầu.
muhasturk 11/03/2016

2
sendAsynyncousRequest không được dùng nữa trong iOS 9
Crashalot

Cảm ơn skywinder, tôi đang sử dụng phương pháp này để tải hình ảnh từ mảng. Tôi muốn khi người dùng nhấn vào cancelnút nó dừng tải xuống. Bạn có biết làm thế nào tôi có thể làm điều này với việc sử dụng phương pháp này? Tôi cần thêm chức năng hủy.
ZAFAR007

44

Swift 2.2 | | Xcode 7.3

Tôi đã nhận được kết quả tuyệt vời !! với thư viện nhanh chóng của AlamofireImage

Nó cung cấp nhiều tính năng như:

  • Tải xuống không đồng bộ
  • Tự động xóa bộ nhớ cache hình ảnh nếu cảnh báo bộ nhớ xảy ra cho ứng dụng
  • Bộ nhớ đệm URL hình ảnh
  • Bộ nhớ đệm hình ảnh
  • Tránh tải xuống trùng lặp

và rất dễ thực hiện cho ứng dụng của bạn

Bước.1 Cài đặt nhóm


Alamofire 3.3.x

nhóm 'Alamofire'

Hình ảnh chính xác

nhóm 'Hình ảnh nổi bật'

Bước.2 nhập và sử dụng

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)

đó là nó!! nó sẽ chăm sóc mọi thứ


Cảm ơn rất nhiều đến những người của Alamofire , vì đã làm cho cuộc sống của các nhà phát triển iD trở nên dễ dàng;)


8
Swift 3: foregroundImage.af_setImage (withURL: downloadURL dưới dạng URL)
thejuki

28

Xcode 8Swift 3

Câu trả lời của Leo Dabus thật tuyệt vời! Tôi chỉ muốn cung cấp một giải pháp chức năng tất cả trong một:

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, có lẽ có nghĩa là "không đồng bộ" ở cuối đó
Fattie

16

Tôi đã gói mã các câu trả lời tốt nhất cho câu hỏi thành một lớp duy nhất, có thể sử dụng lại mở rộng UIImageView, để bạn có thể trực tiếp sử dụng UIImageViews tải không đồng bộ trong bảng phân cảnh của mình (hoặc tạo chúng từ mã).

Đây là lớp học của tôi:

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

và đây là cách sử dụng nó:

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

2
Chúng ta có thực sự cần những cái đó bị ghi đè không? Không phải là những người thừa kế được thừa hưởng? Có vẻ như chúng ta chỉ ghi đè ở đây chỉ để gọi siêu năng lực, điều khiến tôi thấy là dư thừa.
Kỹ sư công nghệ NYC

16

Swift 4 ::

Điều này sẽ hiển thị trình tải trong khi tải hình ảnh. Bạn có thể sử dụng NSCache để lưu trữ hình ảnh tạm thời

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

Sử dụng:-

truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)

1
Nó hoạt động. Chỉ cần sao chép hoạt động Loại bỏ trong trường hợp lỗi quá.
djdance

1
rất hữu ích cho dự án của tôi.
partikles 30/11/19

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
Người dùng

Bất kỳ cơ hội bạn có thể viết lên một cái gì đó không đồng bộ?
Jed Grant

@JedGrant bạn có thể sử dụng Clark_async để vào một chuỗi khác và gọi lại
Matej

Tôi đã phải mở khóa NSData bằng dấu "!" (lưu ý! ở cuối) để làm cho nó hoạt động như thế này: var imageData: NSData = NSData (nội dungOfURL: url, tùy chọn: NSDataReadOptions.DataReadMapped IfSafe, lỗi: & err)!
botbot

13

FYI: Dành cho 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 bị tước quyền. Bạn phải sử dụng NSURLSession. Sẽ tốt hơn khi bạn mã hóa bằng Swift 2.0 và Xcode 7
BilalReffas

11

swift 3 với xử lý lỗi

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

Với phần mở rộng

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

Sử dụng tiện ích mở rộng

myImageView. setCustomImage("url")

Với hỗ trợ 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: Trình tải đơn giản cho các hình ảnh nhỏ (ví dụ: hình thu nhỏ) sử dụng NSCache và luôn chạy trên luồng chính:

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

}

Sử dụng:

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

Tại sao sử dụng singleton với struct? điều này sẽ khiến lớp của bạn trở nên bất biến có thể gây ra sự cố với NSCache của bạn
XcodeNOOB

Cảm ơn đã chỉ ra điều này, tôi vừa đổi nó thành class.
fethica

1
private let cache đã cho tôi lỗi nên đã thay đổi nó thành static và nó hoạt động! Cảm ơn
Hammad Tariq

7

Bạn sẽ muốn làm:

UIImage(data: data)

Trong Swift, họ đã thay thế hầu hết các phương thức nhà máy Objective C bằng các hàm tạo thông thường.

Xem:

https://developer.apple.com/lvern/prerelease/ios/documentation/Swift/Conceptual/BuILDCocoaApps/InteractingWithObjective-CAPIs.html#//apple_Vf/doc/uid/TP40014216-CH4


2
Bản đồ kỹ thuật, không thay thế. Nếu bạn thực hiện phương thức của riêng mình +(instancetype)[MyThing thingWithOtherThing:], bạn cũng sẽ gọi nó như MyThing(otherThing: ...)trong Swift.
Brian Nickel

7

Swift 2 có lỗi Xử lý và tiêu đề yêu cầu tùy chỉnh

Chỉ cần thêm tiện ích mở rộng vào 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()
        }
    }
}

Và sau đó, sử dụng cái mới imageFromUrl(urlString: String)để tải hình ảnh

Sử dụng:

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

trong swift 3, tôi tiếp tục nhận được lỗi này. Có vấn đề gì vậy? Trong dòng này "" "URLSession. Shared.dataTask (với: url) {" "" "" "" Không thể gọi 'dataTask' với danh sách đối số loại '(với: URL, (Dữ liệu?, URLResponse?, Lỗi? ) -> Vô hiệu) '
Aymen BRomdhane

7

Swift 4

Phương pháp này sẽ tải xuống một hình ảnh từ một trang web không đồng bộ và lưu trữ nó vào bộ đệm:

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

Đang sử dụng:

    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
    }

Làm thế nào nó được lưu trữ? Và trong bao lâu?
Ramis

Nó dường như được lưu trữ vĩnh viễn, thật kỳ lạ, nó được lưu trữ trong thư mục Thư viện> Caches. Sử dụng in (NSHomeDirectory ()) để đến vị trí này trên máy tính của bạn khi chạy trên trình giả lập.
Bobby

5

Swift 2.0:

1)

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

HOẶC LÀ

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

2) Thêm phương thức này vào VC hoặc Tiện ích mở rộng.

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

Sử dụng :

self.load_image(" url strig here")

sendAsynyncousRequest không được dùng nữa trong iOS 9
Crashalot

5

Kingfisher là một trong những thư viện tốt nhất để tải hình ảnh vào URL.

URL Github - https://github.com/onevcat/Kingfisher

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

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

5

Đây là mã làm việc để tải / tải hình ảnh từ URL. NSCache tự động và hiển thị hình ảnh giữ chỗ trước khi tải xuống và tải hình ảnh thực tế (Mã 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!
                        }
                    }
                }
            }
        }
    }
}

Sử dụng như thế này:

// 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
Điều duy nhất làm việc với tôi. Vấn đề của tôi là tôi đang triển khai trình phát nhạc và tôi muốn tải hình ảnh trong thông báo khi điện thoại cũng bị đóng và trình xử lý lấy loại UIImage nên tôi phải sử dụng phương pháp này.
JhonnyTawk

4

Phương pháp để có được hình ảnh an toàn và hoạt động với Swift 2.0 và 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)
}

Sau đó, bạn sẽ gọi phương thức này như vậy:

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

Nếu bạn đang cập nhật chế độ xem bằng hình ảnh, bạn sẽ phải sử dụng chế độ này sau "nếu thành công {":

    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
    }

Lý do phần cuối cùng này là cần thiết nếu bạn đang sử dụng hình ảnh trong giao diện người dùng là vì các cuộc gọi mạng mất thời gian. Nếu bạn cố cập nhật giao diện người dùng bằng hình ảnh mà không gọi đến Clark_async như trên, máy tính sẽ tìm hình ảnh trong khi hình ảnh vẫn đang được tìm nạp, thấy rằng không có hình ảnh nào (và) và tiếp tục như thể không có hình ảnh tìm. Đặt mã của bạn bên trong một bao đóng hoàn thành Clark_async nói với máy tính: "Đi, lấy hình ảnh này và khi bạn hoàn thành, sau đó hoàn thành mã này." Bằng cách đó, bạn sẽ có hình ảnh khi mã được gọi và mọi thứ sẽ hoạt động tốt.


4

Nếu bạn đang tìm kiếm một thực hiện rất rất đơn giản. (Điều này làm việc cho tôi trong 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)

Tôi đã triển khai trong chế độ xem bảng với một ô tùy chỉnh chỉ có hình ảnh

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

    }

bạn đúng, đó là vì tải xuống và nén đang diễn ra trên luồng chính. lý tưởng nhất là bạn nên thực hiện không đồng bộ 2 bước này trong một luồng nền, có thể đang sử dụng hàng đợi toàn cầu
Clark_async

Có, bằng cách sử dụng luồng nền, chúng tôi có thể tối ưu hóa tốc độ tải xuống và Nếu cần, chúng tôi có thể thay đổi logic thay vì điều này, chúng tôi có thể sử dụng sdWebImage hoặc khung khác.
Gourav Joshi

2

Tôi khuyên bạn nên sử dụng thư viện Kingfisher để tải xuống hình ảnh không đồng bộ. Phần tốt nhất về việc sử dụng Kingfisher là, nó lưu trữ tất cả các hình ảnh được tải xuống theo mặc định với url hình ảnh dưới dạng id. Lần tới khi bạn yêu cầu tải xuống hình ảnh với URl cụ thể đó, nó sẽ tải nó từ bộ đệm.

Sử dụng:

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

Bạn có thể sử dụng pod SDWebImageđể đạt được điều tương tự. Nó dễ sử dụng. Bạn có thể lấy tài liệu ở đây SDWebImage

Đây là mã mẫu

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

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

cho việc sử dụng

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

1

Điều duy nhất còn thiếu là a!

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

Xin lỗi vì đã trả lời trễ, bạn có thể chính xác hơn về những lỗi bạn nhận được không?
Simon Jensen

1

Swift 2.x trả lời rằng tải hình ảnh xuống tệp (trái ngược với câu trả lời của Leo Dabus, nơi lưu trữ hình ảnh trong bộ nhớ). Dựa trên câu trả lời của Leo Dabus và câu trả lời của Rob từ Lấy dữ liệu từ NSURLSession Tải xuốngTaskWithRequest từ trình xử lý hoàn thành :

    // 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 Tôi đã chọn một chức năng chỉ cần truyền url hình ảnh, khóa bộ đệm sau khi hình ảnh được tạo, đặt nó thành khối hoàn thành.

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

Tôi đã tạo một hàm lớp đơn giản trong Utils.swiftlớp để gọi phương thức đó mà bạn có thể truy cập đơn giản classname.methodnamevà hình ảnh của bạn được lưu trong NSCache bằng ImageCaching.swiftlớp

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

Chúc mừng mã hóa. Chúc mừng :)


1

Swift 4.2 và AlamofireImage

Nếu việc sử dụng thư viện không phải là một vấn đề, bạn có thể làm điều đó bằng sự trợ giúp của AlamofireImage. mẫu của tôi là từ Github của nó

Hình ảnh giữ chỗ Ví dụ:

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)

Nó có nhiều chức năng tiện dụng và phần mở rộng để làm việc với hình ảnh. từ bộ nhớ đệm đến thu nhỏ và thay đổi kích thước hoặc thậm chí áp dụng các bộ lọc trên hình ảnh. nếu hình ảnh quan trọng trong ứng dụng của bạn, tôi khuyên bạn nên sử dụng khung này và tiết kiệm thời gian của bạn.


0

Sử dụng Ascyimageview bạn có thể dễ dàng tải imageurl trong chế độ xem hình ảnh.

hãy để image1Url: URL = URL (chuỗi: "(imageurl)" dưới dạng Chuỗi)! fanteview.imageURL = image1Url


0

Tải hình ảnh từ máy chủ: -

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

Sử dụng :-

  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

Để có hiệu suất tốt hơn trong UITableViewhoặc UICollectionViewsử dụng thư viện trọng lượng nhẹ Tải thông minh lười biếng Bạn có thể sử dụng phương pháp tải lười biếng này nếu bạn muốn tải hình ảnh từ url Không đồng bộ

Thông minh 'Lazy Loading' trong UICollectionViewhoặc UITableViewsử dụng NSOperationNSOperationQueuetrong iOS Vì vậy, trong dự án này, chúng tôi có thể tải xuống nhiều hình ảnh trong bất kỳ Chế độ xem ( UICollectionViewhoặc UITableView) nào bằng cách tối ưu hóa hiệu suất của ứng dụng bằng cách sử dụng OperationOperationQueueđồng thời. Sau đây là những điểm chính của dự án này Tải thông minh lười biếng: Tạo dịch vụ tải xuống hình ảnh. Ưu tiên tải xuống dựa trên khả năng hiển thị của các ô.

Lớp ImageDoadService sẽ tạo một cá thể đơn lẻ và có cá thể NSCache để lưu trữ các hình ảnh đã được tải xuống. Chúng tôi đã kế thừa lớp Hoạt động thành TOperation để điều chỉnh chức năng theo nhu cầu của chúng tôi. Tôi nghĩ rằng các thuộc tính của lớp con hoạt động là khá rõ ràng về chức năng. Chúng tôi đang theo dõi sự thay đổi hoạt động của nhà nước bằng cách sử dụng KVO.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.