ฉันสามารถโหลด UIImage จาก URL ได้หรือไม่


134

ฉันมี URL สำหรับรูปภาพ (ได้มาจาก UIImagePickerController) แต่ฉันไม่มีรูปภาพในหน่วยความจำอีกต่อไป (URL ถูกบันทึกจากการเรียกใช้แอพก่อนหน้านี้) ฉันสามารถโหลด UIImage จาก URL ซ้ำได้หรือไม่

ฉันเห็นว่า UIImage มี imageWithContentsOfFile: แต่ฉันมี URL ฉันสามารถใช้ dataWithContentsOfURL ของ NSData เพื่ออ่าน URL ได้หรือไม่

แก้ไข 1


จากคำตอบของ @ Daniel ฉันลองใช้รหัสต่อไปนี้ แต่ไม่ได้ผล ...

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

เมื่อฉันรันคอนโซลจะแสดง:

-[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'

มองไปที่สแต็คโทรฉันโทร URLWithString ซึ่งเรียก URLWithString: relativeToURL :, แล้ว initWithString: relativeToURL :, แล้ว _CFStringIsLegalURLString แล้ว CFStringGetLength แล้วforwarding_prep_0แล้วส่งต่อแล้ว - [NSObject doesNotRecognizeSelector]

มีความคิดว่าทำไม NSString ของฉัน (ที่อยู่ของ photoURL คือ 0x536fbe0) ไม่ตอบสนองต่อความยาว? ทำไมจึงบอกว่าไม่ตอบสนองต่อ - [NSURL length]? ไม่รู้ว่า param เป็น NSString ไม่ใช่ NSURL?

แก้ไข 2


ตกลงปัญหาเดียวของรหัสคือสตริงที่จะแปลง URL ถ้าฉันฮาร์ดโค้ดสตริงทุกอย่างก็ใช้ได้ดี มีบางอย่างผิดปกติกับ NSString ของฉันและถ้าฉันคิดไม่ออกฉันเดาว่าน่าจะเป็นคำถามอื่น เมื่อแทรกบรรทัดนี้ (ฉันวางเส้นทางจากบันทึกคอนโซลด้านบน) มันใช้งานได้ดี:

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

ดูเหมือนว่า photoURL เป็น NSURL อยู่แล้วไม่ใช่ NSString เนื่องจาก NSLog จัดการ
วาด

@drawn: ดูเหมือนข้อผิดพลาดในเอกสาร มันบอกว่า UIImagePickerControllerMediaURL เป็น NSString แต่จริงๆแล้วมันเป็นวัตถุ NSURL
progrmr

DLImageLoader ไลบรารีนั้นเหลือเชื่อ หินแข็งไม่มี doco คำสั่งเดียวและทุกอย่างสมบูรณ์แบบ สิ่งที่พบ
Fattie

ฉันสอง (สาม?) DLImageLoader ฉันไม่แน่ใจว่าความคิดเห็นเกี่ยวกับเรื่องนี้ในหน้านี้มีวัตถุประสงค์หรือไม่ แต่ฉันพยายามแล้วและมันก็ใช้ได้ผลดีมาก ฉันมี UIImageView ภายใน UITableViewCell สิ่งที่ฉันทำคือแทนที่ UIImageView ด้วย DLImageView จากนั้นเรียกว่า imageFromUrl: วิธีการโหลดรูปภาพและทุกอย่างก็ใช้งานได้ - การโหลดแบบอะซิงโครนัสการแคชและอื่น ๆ อาจไม่ง่ายกว่านี้
itnAAnti

DLImageLoader ยังคงยอดเยี่ยมอีกหนึ่งสิ่งที่ดีคือHanekeแม้ว่าจะมีความทุกข์เล็กน้อยจากการไม่ได้รับการดูแล
Fattie

คำตอบ:


321

คุณสามารถทำได้ด้วยวิธีนี้ (พร้อมกัน แต่กะทัดรัด):

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

แนวทางที่ดีกว่ามากคือการใช้ LazyTableImages ของ Apple เพื่อรักษาการโต้ตอบ


1
ข้อมูลไม่จำเป็นต้องแปลงจากรูปแบบไฟล์ PNG (หรือ JPG) เป็นข้อมูล UIImage ใช่หรือไม่ UIImage คิดออกหรือไม่?
progrmr

2
เดาว่าฉันควรจะเป็น RTFM มันบอกถูกต้องใน UIImage Class Reference ว่ารูปแบบไฟล์ใดบ้างที่รองรับได้และ imageWithData: บอกว่ามันอาจเป็นข้อมูลจากไฟล์ดูเหมือนจะใช้งานได้
progrmr

@ แดเนียล: ใช้ไม่ได้ฉันแก้ไขคำถามเพื่อรวมรหัสจริงและข้อมูลข้อยกเว้น เป็นเรื่องแปลกประหลาดเล็กน้อย
progrmr

@ แดเนียล: มันใช้งานได้ถ้าฉันใช้ค่าคงที่สตริงแทน NSString ที่ฉันส่งผ่านดังนั้นปัญหาล่าสุดนี้มีบางอย่างผิดปกติกับ NSString ของฉันไม่ใช่ปัญหากับรหัส NSURL / NSData / UIImage ที่ใช้งานได้ ขอบคุณ Daniel!
progrmr

หากคุณใช้ภาพเพียงภาพเดียวและกำลังมองหาวิธีแก้ไขอย่างรวดเร็วคุณสามารถเขียนโค้ดเล็กน้อยที่เก็บภาพเดียวได้
MrDatabase

27

คุณสามารถลองใช้SDWebImageโดยให้:

  1. โหลดแบบอะซิงโครนัส
  2. แคชสำหรับการใช้งานออฟไลน์
  3. รูปภาพตัวยึดที่จะปรากฏขณะโหลด
  4. ทำงานได้ดีกับ UITableView

ตัวอย่างด่วน:

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

2
ฉันได้แก้ไขไลบรารีนั้นเล็กน้อยและรวมเข้ากับ UIImage + Resize เพื่อเพิ่มความสามารถในการปรับขนาด / ครอบตัดให้กับมัน หากคุณต้องการลองดูที่github.com/toptierlabs/ImageCacheResize
Tony

1
ตัวอย่างนี้เติมข้อมูลUIImageViewไฟล์. SDWebImageยังช่วยให้คุณเติมข้อมูลUIImageโดยตรงโดยใช้SDWebImageManager - (void) downloadWithURL:...ไฟล์. ดูตัวอย่างของพวกเขาในอ่านฉัน
bendytree

10

และรุ่นที่รวดเร็ว:

   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

หากคุณกำลังจริงๆอย่างในเชิงบวกแน่ใจว่า NSURL เป็น URL ของไฟล์เช่น[url isFileURL]มีการประกันเพื่อกลับจริงในกรณีของคุณแล้วคุณก็สามารถใช้:

[UIImage imageWithContentsOfFile:url.path]

7

รับDLImageLoaderและลองใช้รหัสต่อไปนี้

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

                          }];

อีกตัวอย่างในโลกแห่งความเป็นจริงทั่วไปของการใช้ DLImageLoader ซึ่งอาจช่วยใครบางคน

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

อย่างที่ฉันพูดถึงข้างต้นห้องสมุดที่ยอดเยี่ยมอีกแห่งที่ควรพิจารณาในปัจจุบันคือHaneke (น่าเสียดายที่มันไม่เบาเท่า)


1
SDWebImage เป็นไลบรารีที่ได้รับความนิยมมากที่สุดใน Objective-C และ KingFisher คือพอร์ต Swift
XY

1
จริง แต่ DLImageLoader ดีกว่า! :)
Fattie

5

ลองใช้รหัสนี้คุณสามารถตั้งค่าการโหลดรูปภาพได้เพื่อให้ผู้ใช้ทราบว่าแอปของคุณกำลังโหลดรูปภาพจาก 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
ฉันชอบโซลูชันนี้เนื่องจากไม่ต้องโหลดเฟรมเวิร์กของบุคคลที่สามหรือสร้างอินสแตนซ์คิวการโหลดข้อมูล ฯลฯ
BillyRayCyrus

4

ตรวจสอบAsyncImageViewให้มากกว่าที่นี่ โค้ดตัวอย่างที่ดีและอาจใช้งานได้ "ทันที" สำหรับคุณ


ตัวอย่างที่น่าสนใจแนวคิดนี้คล้ายกับตัวอย่าง LazyTableImages ของ Apple ที่กล่าวถึงในคำตอบก่อนหน้านี้
progrmr

คล้ายกัน แต่ระวังว่า AsyncImageView ไม่ทำงานในตารางอย่างน้อยก็ไม่ใช่เมื่อคุณรีไซเคิลเซลล์ตาราง (เท่าที่ควร)
13

4

AFNetworkingให้การโหลดภาพแบบ async ลงใน UIImageView พร้อมการสนับสนุนตัวยึดตำแหน่ง นอกจากนี้ยังรองรับระบบเครือข่าย async สำหรับการทำงานกับ API โดยทั่วไป


3

ตรวจสอบให้แน่ใจว่าเปิดใช้งานการตั้งค่านี้จาก iOS 9:

การตั้งค่าความปลอดภัยการขนส่งของแอปในInfo.plistเพื่อให้แน่ใจว่าโหลดรูปภาพจาก URL เพื่อให้สามารถดาวน์โหลดรูปภาพและตั้งค่าได้

ป้อนคำอธิบายภาพที่นี่

และเขียนรหัสนี้:

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

2

วิธีใช้ Swift Extensionเพื่อUIImageView(ซอร์สโค้ดที่นี่ ):

การสร้างคุณสมบัติที่คำนวณสำหรับ 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()
            })
        }
    }

Custom Initializer และ 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

วิธีที่ดีที่สุดและง่ายที่สุดในการโหลดรูปภาพผ่าน URL คือรหัสนี้:

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

แทนที่imgUrlโดยคุณImageURL
แทนที่โดยคุณimgViewUIImageView

มันจะโหลด Image ในเธรดอื่นดังนั้นมันจะไม่ทำให้การโหลดแอพของคุณช้าลง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.