URL에서 UIImage를로드 할 수 있습니까?


134

이미지의 URL이 있지만 (UIImagePickerController에서 가져옴) 더 이상 이미지가 메모리에 없습니다 (URL은 앱의 이전 실행에서 저장되었습니다). URL에서 UIImage를 다시로드 할 수 있습니까?

UIImage에 imageWithContentsOfFile이 있지만 URL이 있습니다. NSData의 dataWithContentsOfURL :을 사용하여 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 : relativeToURL :, initWithString : relativeToURL :, _CFStringIsLegalURLString, CFStringGetLength, forwarding_prep_0 , 전달 ,-[NSObject does notRecognizeSelector] 를 호출하는 URLWithString을 호출합니다 .

내 NSString (photoURL의 주소는 0x536fbe0)이 길이에 응답하지 않는 이유가 있습니까? -[NSURL 길이]에 응답하지 않는 이유는 무엇입니까? param이 NSURL이 아닌 NSString이라는 것을 모르십니까?

편집 2


코드의 유일한 문제는 문자열을 URL로 변환하는 것입니다. 문자열을 하드 코딩하면 다른 모든 것이 잘 작동합니다. 따라서 NSString에 문제가 있으며 알아낼 수 없다면 다른 질문으로 들어가야한다고 생각합니다. 이 줄을 삽입하면 (위의 콘솔 로그에서 경로를 붙여 넣었습니다) 제대로 작동합니다.

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

NSLog가 처리 한 경우 photoURL은 이미 NSString이 아닌 NSURL 인 것처럼 보입니다.
— 그려진

@drawn : 문서의 오류처럼 보입니다. UIImagePickerControllerMediaURL은 NSString이지만 실제로는 NSURL 객체라고 말합니다.
— progrmr

DLImageLoader 라이브러리는 믿을 수 없습니다. 견고하고 도코가 없으며 하나의 명령으로 모든 것이 완벽합니다. 이게 뭐야
— Fattie

나는 두 번째 (세 번째?) DLImageLoader입니다. 이 페이지에 대한 의견이 객관적인지 여부에 대해 회의적이었습니다. 그러나 어쨌든 시도해 보았으며 매우 잘 작동합니다. UITableViewCell 내에 UIImageView가 있습니다. UIImageView를 DLImageView로 바꾸고 imageFromUrl : 메소드를 호출하여 이미지를로드하기 만하면 비동기 로딩, 캐싱 등 모든 것이 작동합니다.
— itnAAnti

DLImageLoader는 여전히 환상적이며, 또 다른 좋은 하나는 Haneke 입니다.
— Fattie

답변:


319

이 방법으로 (동기식이지만 컴팩트하게) 할 수 있습니다.

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

훨씬 더 좋은 방법은 Apple의 LazyTableImage를 사용하여 대화 형 기능을 유지하는 것입니다.


1
데이터를 PNG (또는 JPG) 파일 형식에서 UIImage 데이터로 변환 할 필요가 없습니까? 아니면 UIImage가 어떻게 든 알아낼 수 있습니까?
— progrmr

2
RTFM을 사용해야한다고 생각합니다 .UIImage 클래스 참조에서 지원 할 수있는 파일 형식과 imageWithData : 파일의 데이터 일 수 있으며 작동하는 것처럼 들립니다.
— progrmr

@Daniel : 작동하지 않았습니다. 실제 코드와 예외 정보를 포함하도록 질문을 편집했습니다. 조금 기괴하다.
— progrmr

@Daniel : 전달한 NSString 대신 문자열 상수를 사용하면 작동합니다. 따라서이 최신 문제는 NSString / NSData / UIImage 코드의 문제가 아닌 NSString의 문제입니다. 고마워 다니엘!
— 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 + 크기 조정과 통합했습니다. 필요한 경우 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]귀하의 경우에 true를 돌려 보장, 당신은 간단하게 사용할 수 있습니다 :

[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
True이지만 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
는 등, 데이터 로딩 큐를 어떤 제 3 자 프레임 워크를로드하거나 인스턴스화 필요로하지 않았기 때문에 나는이 솔루션을 선호
— BillyRayCyrus

4

여기에AsyncImageView 제공된 것을 확인 하십시오 . 좋은 예제 코드이며, "바로"바로 사용할 수도 있습니다.


흥미로운 예는 개념적으로 이전 답변에서 언급 한 Apple의 LazyTableImages 예제와 매우 유사합니다.
— progrmr

비슷하지만 AsyncImageView는 실제로 테이블 셀을 재활용 할 때 (필요하지 않은 경우) 테이블에서 작동하지 않습니다.
— n13

4

AFNetworking 은 자리 표시자를 지원하여 UIImageView에 비동기 이미지로드를 제공합니다. 또한 일반적인 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(소스 코드 here ) :

관련 컴퓨팅 속성 생성 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()
            })
        }
    }

커스텀 이니셜 라이저 및 세터

    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
대체 imgView당신에 의해 UIImageView.

다른 스레드에 이미지를로드하므로 앱로드가 느려지지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.