[ios] Swift의 URL에서 이미지로드 / 다운로드

내 응용 프로그램의 URL에서 이미지를로드하고 싶습니다. 먼저 Objective-C로 시도했지만 Swift에서는 컴파일 오류가 발생했습니다.

‘imageWithData’를 사용할 수 없습니다 : 객체 생성 사용 ‘UIImage (data :)’

내 기능 :

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

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

누군가 imageWithData:Swift와 작동하지 않는 이유를 설명 하고 문제를 어떻게 해결할 수 있습니까 ?



답변

Xcode 8 이상 • Swift 3 이상

동 기적으로 :

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

비동기 적으로 :

URL에서 이미지 데이터를 가져 오기 위해 완료 핸들러로 메소드를 작성하십시오.

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

이미지 다운로드 방법 생성 (작업 시작)

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

용법:

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

연장 :

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

용법:

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


답변

(Swift 4 업데이트)
원래 질문에 직접 대답하기 위해 게시 된 Objective-C 스 니펫과 동일한 기능을 제공합니다.

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

기권:

Data(contentsOf:)메소드는 코드가 실행되는 동일한 스레드에서 URL의 컨텐츠를 동 기적 으로 다운로드 하므로 애플리케이션의 기본 스레드에서이를 호출 하지 마십시오 .

UI를 차단하지 않고 동일한 코드를 비동기식으로 실행하는 쉬운 방법은 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!)
    }
}

즉, 실제 응용 프로그램에서 최상의 사용자 경험을 원하고 동일한 이미지를 여러 번 다운로드하지 않으려면 다운로드뿐만 아니라 캐시해야 할 수도 있습니다. 이미 매우 매끄럽고 사용하기 쉬운 라이브러리가 많이 있습니다. 개인적으로 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) 

그리고 그게 다야


답변

이미지를 비동기식 으로로드 하려면 빠른 코드 에이 작은 확장을 추가하십시오.

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

그리고 이런 식으로 사용하십시오 :

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


답변

스위프트 2.2 || Xcode 7.3

나는 놀라운 결과를 얻었다 !! 와 AlamofireImage의 빠른 라이브러리

다음과 같은 여러 기능을 제공합니다.

  • 비동기 적으로 다운로드
  • 앱에 메모리 경고가 발생하면 이미지 캐시 자동 제거
  • 이미지 URL 캐싱
  • 이미지 캐싱
  • 중복 다운로드 방지

앱을 구현하기가 매우 쉽습니다.

1 단계 포드 설치


알라모 파이어 3.3.x

포드 ‘Alamofire’

AlamofireImage 2.4.x

포드 ‘AlamofireImage’

2 단계 가져 오기 및 사용

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)

그게 다야 !! 그것은 모든 것을 돌볼 것입니다


iDevelopers의 삶 을 편하게 해준 Alamofire 녀석들 에게 큰 감사를드립니다 .)


답변

Xcode 8스위프트 3

Leo Dabus의 답변은 대단합니다! 방금 올인원 기능 솔루션을 제공하고 싶었습니다.

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


답변

질문에 가장 적합한 답변의 코드를 UIImageView를 확장하는 재사용 가능한 단일 클래스로 래핑하여 스토리 보드에서 비동기 로딩 UIImageView를 직접 사용하거나 코드에서 만들 수 있습니다.

여기 내 수업이 있습니다.

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

사용 방법은 다음과 같습니다.

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


답변

스위프트 4 : :

이미지를로드하는 동안 로더가 표시됩니다. 이미지를 일시적으로 저장 하는 NSCache 를 사용할 수 있습니다

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

용법:-

truckImageView.loadImageUsingCache(withUrl: currentTruck.logoString)