Tôi có thể tải UIImage từ URL không?


134

Tôi có một URL cho một hình ảnh (lấy nó từ UIImagePickerControll) nhưng tôi không còn hình ảnh trong bộ nhớ (URL đã được lưu từ lần chạy ứng dụng trước đó). Tôi có thể tải lại UIImage từ URL không?

Tôi thấy rằng UIImage có một hình ảnhWithContentsOfFile: nhưng tôi có một URL. Tôi có thể sử dụng dữ liệu của NSDataWithContentsOfURL: để đọc URL không?

EDIT1


dựa trên câu trả lời của @ Daniel, tôi đã thử đoạn mã sau nhưng không được ...

NSLog(@"%s %@", __PRETTY_FUNCTION__, photoURL);     
if (photoURL) {
    NSURL* aURL = [NSURL URLWithString:photoURL];
    NSData* data = [[NSData alloc] initWithContentsOfURL:aURL];
    self.photoImage = [UIImage imageWithData:data];
    [data release];
}

Khi tôi chạy nó, giao diện điều khiển hiển thị:

-[PhotoBox willMoveToWindow:] file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG
*** -[NSURL length]: unrecognized selector sent to instance 0x536fbe0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL length]: unrecognized selector sent to instance 0x536fbe0'

Nhìn vào các cuộc gọi stack, tôi gọi URLWithString, trong đó kêu gọi URLWithString: relativeToURL :, sau đó initWithString: relativeToURL :, sau đó _CFStringIsLegalURLString, sau đó CFStringGetLength, sau đó forwarding_prep_0 , sau đó chuyển tiếp , sau đó - [NSObject doesNotRecognizeSelector].

Có ai biết tại sao NSString của tôi (địa chỉ của photoURL là 0x536fbe0) không đáp ứng với độ dài không? Tại sao nó nói nó không đáp ứng - [NSURL chiều dài]? Nó không biết rằng param là NSString chứ không phải NSURL?

EDIT2


OK, vấn đề duy nhất với mã là chuyển đổi chuỗi thành URL. Nếu tôi mã hóa chuỗi, mọi thứ khác đều hoạt động tốt. Vì vậy, có điều gì đó không ổn với NSString của tôi và nếu tôi không thể tìm ra nó, tôi đoán đó sẽ là một câu hỏi khác. Với dòng này được chèn (Tôi đã dán đường dẫn từ nhật ký giao diện điều khiển ở trên), nó hoạt động tốt:

photoURL = @"file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG";

Có vẻ như photoURL đã là NSURL, không phải là NSString, do NSLog đã xử lý nó.
rút ra vào

@drawn: Có vẻ như là một lỗi trong tài liệu. Nó nói rằng UIImagePickerControllMediaURL là một NSString nhưng thực ra nó là một đối tượng NSURL.
progrmr

Thư viện DLImageLoader là TUYỆT VỜI. đá rắn, không doco, một lệnh và mọi thứ đều hoàn hảo. Thật là một tìm thấy.
Fattie

Tôi thứ hai (thứ ba?) DLImageLoader. Tôi đã hoài nghi về việc liệu các bình luận về nó trên trang này có khách quan hay không - nhưng dù sao tôi cũng đã thử và nó hoạt động rất độc đáo. Tôi có một UIImageView trong UITableViewCell. Tất cả những gì tôi đã làm là thay thế UIImageView bằng DLImageView, sau đó được gọi là phương thức imageFromUrl: để tải hình ảnh và tất cả chỉ hoạt động - tải không đồng bộ, bộ đệm, v.v. không thể dễ dàng hơn.
itnAAnti

DLImageLoader vẫn tuyệt vời, một cái tốt khác là Haneke , mặc dù nó chịu đựng một chút vì không được duy trì.
Fattie

Câu trả lời:


319

Bạn có thể làm theo cách này (đồng bộ, nhưng nhỏ gọn):

UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:MyURL]]];

Cách tiếp cận tốt hơn nhiều là sử dụng LazyTableImages của Apple để duy trì tính tương tác.


1
Không phải dữ liệu cần phải được chuyển đổi từ định dạng tệp PNG (hoặc JPG) sang dữ liệu UIImage? Hay là UIImage tìm ra bằng cách nào đó?
progrmr

2
Đoán tôi chỉ nên RTFM, nó nói ngay trong UIImage Class Reference những định dạng tệp nào nó có thể hỗ trợ và imageWithData: nói rằng nó có thể là dữ liệu từ một tệp, nghe có vẻ như nó sẽ hoạt động.
progrmr

@Daniel: không hoạt động, tôi đã chỉnh sửa câu hỏi của mình để bao gồm mã thực tế và thông tin ngoại lệ. Đó là một chút kỳ quái.
progrmr

@Daniel: nó hoạt động nếu tôi sử dụng hằng chuỗi thay vì NSString mà tôi đã truyền vào. Vì vậy, sự cố mới nhất này có vấn đề với NSString của tôi, không phải là vấn đề với mã NSURL / NSData / UIImage hoạt động. Cảm ơn Daniel!
progrmr

Nếu bạn đang sử dụng chỉ một hình ảnh và bạn đang tìm cách khắc phục nhanh, bạn có thể chỉ cần viết một chút mã lưu trữ hình ảnh duy nhất.
MrDatabase

27

Bạn có thể thử SDWebImage , nó cung cấp:

  1. Tải không đồng bộ
  2. Bộ nhớ đệm để sử dụng ngoại tuyến
  3. Đặt hình ảnh chủ sở hữu để xuất hiện trong khi tải
  4. Hoạt động tốt với UITableView

Ví dụ nhanh:

    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

2
Tôi đã sửa đổi thư viện đó một chút và tích hợp nó với UIImage + Thay đổi kích thước để thêm khả năng Thay đổi kích thước / Cắt cho nó. Nếu bạn cần kiểm tra nó tại github.com/toptierlabs/ImageCacheResize
Tony

1
Ví dụ này cư trú a UIImageView. SDWebImagecũng cho phép bạn nhập UIImagetrực tiếp bằng cách sử dụng SDWebImageManager - (void) downloadWithURL:.... Xem ví dụ của họ trên đọc tôi.
uốn cong

10

Và phiên bản nhanh chóng:

   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)

7

Nếu bạn thực sự , hoàn toàn chắc chắn tích cực rằng NSURL là một url tệp, nghĩa [url isFileURL]là được đảm bảo trả về đúng trong trường hợp của bạn, thì bạn chỉ cần sử dụng:

[UIImage imageWithContentsOfFile:url.path]

7

nhận DLImageLoader và thử mã folowing

   [DLImageLoader loadImageFromURL:imageURL
                          completed:^(NSError *error, NSData *imgData) {
                              imageView.image = [UIImage imageWithData:imgData];
                              [imageView setContentMode:UIViewContentModeCenter];

                          }];

Một ví dụ điển hình khác trong thế giới thực về việc sử dụng DLImageLoader, có thể giúp ai đó ...

PFObject *aFacebookUser = [self.fbFriends objectAtIndex:thisRow];
NSString *facebookImageURL = [NSString stringWithFormat:
    @"http://graph.facebook.com/%@/picture?type=large",
    [aFacebookUser objectForKey:@"id"] ];

__weak UIImageView *loadMe = self.userSmallAvatarImage;
// ~~note~~ you my, but usually DO NOT, want a weak ref
[DLImageLoader loadImageFromURL:facebookImageURL
   completed:^(NSError *error, NSData *imgData)
    {
    if ( loadMe == nil ) return;

    if (error == nil)
        {
        UIImage *image = [UIImage imageWithData:imgData];
        image = [image ourImageScaler];
        loadMe.image = image;
        }
    else
        {
        // an error when loading the image from the net
        }
    }];

Như tôi đã đề cập ở trên, một thư viện tuyệt vời khác để xem xét những ngày này là Haneke (tiếc là nó không nhẹ như vậy).


1
SDWebImage là thư viện phổ biến nhất trong Objective-C và KingFisher là cổng Swift.
XY

1
Đúng, nhưng DLImageLoader tốt hơn! :)
Fattie

5

Hãy thử mã này, bạn có thể đặt tải hình ảnh với nó, để người dùng biết rằng ứng dụng của bạn đang tải hình ảnh từ url:

UIImageView *yourImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"loading.png"]];
    [yourImageView setContentMode:UIViewContentModeScaleAspectFit];

    //Request image data from the URL:
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://yourdomain.com/yourimg.png"]];

        dispatch_async(dispatch_get_main_queue(), ^{
            if (imgData)
            {
                //Load the data into an UIImage:
                UIImage *image = [UIImage imageWithData:imgData];

                //Check if your image loaded successfully:
                if (image)
                {
                    yourImageView.image = image;
                }
                else
                {
                    //Failed to load the data into an UIImage:
                    yourImageView.image = [UIImage imageNamed:@"no-data-image.png"];
                }
            }
            else
            {
                //Failed to get the image data:
                yourImageView.image = [UIImage imageNamed:@"no-data-image.png"];
            }
        });
    });

2
Tôi thích giải pháp này vì nó không yêu cầu tải bất kỳ khung bên thứ 3 nào hoặc khởi tạo hàng đợi tải dữ liệu, v.v.
BillyRayCyrus

4

Kiểm tra AsyncImageViewđược cung cấp ở đây . Một số mã ví dụ tốt và thậm chí có thể sử dụng được ngay "ngoài hộp" cho bạn.


Ví dụ thú vị, về khái niệm rất giống với ví dụ LazyTableImages của Apple được đề cập trong câu trả lời trước đó.
progrmr

Tương tự nhưng hãy cẩn thận khi AsyncImageView thực sự không hoạt động trong các bảng, ít nhất là không khi bạn tái chế các ô của bảng (như bạn nên).
n13

4

AFNetworking cung cấp tải hình ảnh không đồng bộ vào UIImageView với sự hỗ trợ giữ chỗ. Nó cũng hỗ trợ kết nối mạng không đồng bộ để làm việc với các API nói chung.


3

Đảm bảo bật cài đặt này từ iOS 9:

Cài đặt bảo mật vận chuyển ứng dụng trong Info.plist để đảm bảo tải hình ảnh từ URL để nó cho phép tải xuống hình ảnh và thiết lập nó.

nhập mô tả hình ảnh ở đây

Và viết mã này:

NSURL *url = [[NSURL alloc]initWithString:@"http://feelgrafix.com/data/images/images-1.jpg"];
NSData *data =[NSData dataWithContentsOfURL:url];
quickViewImage.image = [UIImage imageWithData:data];

2

Cách sử dụng Tiện ích mở rộng Swift đến UIImageView(mã nguồn tại đây ):

Tạo tài sản tính toán cho Associated UIActivityIndicatorView

import Foundation
import UIKit
import ObjectiveC

private var activityIndicatorAssociationKey: UInt8 = 0

extension UIImageView {
    //Associated Object as Computed Property
    var activityIndicator: UIActivityIndicatorView! {
        get {
            return objc_getAssociatedObject(self, &activityIndicatorAssociationKey) as? UIActivityIndicatorView
        }
        set(newValue) {
            objc_setAssociatedObject(self, &activityIndicatorAssociationKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN))
        }
    }

    private func ensureActivityIndicatorIsAnimating() {
        if (self.activityIndicator == nil) {
            self.activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
            self.activityIndicator.hidesWhenStopped = true
            let size = self.frame.size;
            self.activityIndicator.center = CGPoint(x: size.width/2, y: size.height/2);
            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                self.addSubview(self.activityIndicator)
                self.activityIndicator.startAnimating()
            })
        }
    }

Trình khởi tạo tùy chỉnh và Setter

    convenience init(URL: NSURL, errorImage: UIImage? = nil) {
        self.init()
        self.setImageFromURL(URL)
    }

    func setImageFromURL(URL: NSURL, errorImage: UIImage? = nil) {
        self.ensureActivityIndicatorIsAnimating()
        let downloadTask = NSURLSession.sharedSession().dataTaskWithURL(URL) {(data, response, error) in
            if (error == nil) {
                NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                    self.activityIndicator.stopAnimating()
                    self.image = UIImage(data: data)
                })
            }
            else {
                self.image = errorImage
            }
        }
        downloadTask.resume()
    }
}

0

Cách tốt nhất và dễ dàng để tải hình ảnh qua Url là theo Mã này:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData *data =[NSData dataWithContentsOfURL:[NSURL URLWithString:imgUrl]];

    dispatch_async(dispatch_get_main_queue(), ^{
        imgView.image= [UIImage imageWithData:data];
    });
});

Thay thế imgUrlbởi bạn ImageURL
thay thế imgViewbởi bạn UIImageView.

Nó sẽ tải Hình ảnh trong một Chủ đề khác, vì vậy Nó sẽ không làm chậm tải Ứng dụng của bạn.

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.