【问题标题】:Can I load a UIImage from a URL?我可以从 URL 加载 UIImage 吗?
【发布时间】:2011-02-16 11:15:23
【问题描述】:

我有一个图像的 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,它调用 URLWithString:relativeToURL:,然后是 initWithString:relativeToURL:,然后是 _CFStringIsLegalURLString,然后是 CFStringGetLength,然后是 forwarding_prep_0,然后是 forwarding,然后是 -[NSObject doesNotRecognizeSelector]。

知道为什么我的 NSString(photoURL 的地址是 0x536fbe0)不响应长度吗?为什么它说它不响应 -[NSURL 长度]?难道不知道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 对象。
  • DLImageLoader 库令人难以置信。坚如磐石,没有 doco,一个命令,一切都很完美。多么好的发现。
  • 我第二(第三?)DLImageLoader。我怀疑这个页面上关于它的 cmets 是否客观 - 但我还是尝试了它,它确实工作得很好。我在 UITableViewCell 中有一个 UIImageView。我所做的只是将 UIImageView 替换为 DLImageView,然后调用 imageFromUrl: 方法来加载图像,一切正常——异步加载、缓存等。再简单不过了。
  • DLImageLoader 仍然很棒,另一个不错的是 Haneke,虽然它因维护不善而受到了一点影响。

标签: ios iphone uiimage uiimagepickercontroller


【解决方案1】:

你可以这样做(同步,但紧凑):

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

更好的方法是使用 Apple 的 LazyTableImages 来保持交互性。

【讨论】:

  • 数据是否需要从PNG(或JPG)文件格式转换为UIImage数据?还是 UIImage 以某种方式解决了这个问题?
  • 猜我应该只是 RTFM,它在 UIImage Class Reference 中说它可以支持哪些文件格式,而 imageWithData: 说它可以是来自文件的数据,听起来应该可以。
  • @Daniel:没用,我编辑了我的问题以包含我的实际代码和异常信息。这有点奇怪。
  • @Daniel:如果我使用字符串常量而不是我传入的 NSString,它确实有效。所以这个最新的问题是我的 NSString 有问题,而不是 NSURL/NSData/UIImage 的问题有效的代码。谢谢丹尼尔!
  • 如果您只使用一张图片并且正在寻找快速解决方案,您可以编写一些代码来缓存单个图片。
【解决方案2】:

你可以试试SDWebImage,它提供:

  1. 异步加载
  2. 缓存以供离线使用
  3. 加载时显示的占位符图片
  4. 与 UITableView 配合得很好

快速示例:

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

【讨论】:

  • 我对该库进行了一些修改,并将其与 UIImage+Resize 集成,以便为其添加 Resize/Crop 功能。如果您需要,请查看github.com/toptierlabs/ImageCacheResize
  • 此示例填充UIImageViewSDWebImage 还允许您直接使用SDWebImageManager - (void) downloadWithURL:... 填充UIImage。在阅读我的文章中查看他们的示例。
【解决方案3】:

还有 swift 版本:

   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)

【讨论】:

    【解决方案4】:

    如果您真的,绝对肯定确保 NSURL 是文件 url,即[url isFileURL] 在您的情况下保证返回 true,那么您可以只需使用:

    [UIImage imageWithContentsOfFile:url.path]
    

    【讨论】:

      【解决方案5】:

      获取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(不幸的是它没有那么轻量级)。

      【讨论】:

      • SDWebImage 是 Objective-C 中最流行的库,而 KingFisher 是 Swift 端口。
      • True ,但 DLImageLoader 更好! :)
      【解决方案6】:

      试试这个代码,你可以用它设置加载图片,让用户知道你的应用正在从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"];
                  }
              });
          });
      

      【讨论】:

      • 我更喜欢这个解决方案,因为它不需要加载任何 3rd 方框架或实例化数据加载队列等。
      【解决方案7】:

      查看here 提供的AsyncImageView。一些很好的示例代码,甚至可以“开箱即用”供您使用。

      【讨论】:

      • 有趣的例子,它在概念上与之前答案中提到的 Apple 的 LazyTableImages 示例非常相似。
      • 类似,但要注意 AsyncImageView 在表格中确实不起作用,至少在您回收表格单元格时不起作用(正如您应该这样做的那样)。
      【解决方案8】:

      AFNetworking 提供异步图像加载到具有占位符支持的 UIImageView。它还支持异步网络以使用一般的 API。

      【讨论】:

        【解决方案9】:

        确保从 iOS 9 启用此设置:

        App Transport Security SettingsInfo.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];
        

        【讨论】:

          【解决方案10】:

          使用Swift的方式ExtensionUIImageView(源代码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()
              }
          }
          

          【讨论】:

            【解决方案11】:

            通过 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

            它将在另一个线程中加载图像,因此不会减慢您的应用程序加载速度。

            【讨论】:

              【解决方案12】:

              本地网址非常简单,只需使用这个:

              UIImage(contentsOfFile: url.path)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-09-18
                • 2013-07-23
                • 1970-01-01
                相关资源
                最近更新 更多