【问题标题】:Set UIImageView image using a url使用 url 设置 UIImageView 图像
【发布时间】:2011-02-10 20:54:24
【问题描述】:

是否可以读取图像的 url 并将 UIImageView 设置为该 url 处的图像?

【问题讨论】:

    标签: iphone uiimageview


    【解决方案1】:

    对于如此简单的任务,我强烈建议不要集成诸如 Three20 之类的项目,该库是一个怪物,而且启动和运行起来并不容易。

    我会推荐这种方法:

    NSString *imageUrl = @"http://www.foo.com/myImage.jpg";
    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageUrl]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        myImageView.image = [UIImage imageWithData:data];
    }];
    

    为 Swift 3.0 编辑

    let urlString = "http://www.foo.com/myImage.jpg"
    guard let url = URL(string: urlString) else { return }
    URLSession.shared.dataTask(with: url) { (data, response, error) in
        if error != nil {
            print("Failed fetching image:", error)
            return
        }
    
        guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
            print("Not a proper HTTPURLResponse or statusCode")
            return
        }
    
        DispatchQueue.main.async {
            self.myImageView.image = UIImage(data: data!)
        }
    }.resume()
    

    *为 Swift 2.0 编辑

    let request = NSURLRequest(URL: NSURL(string: urlString)!)
    
    NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
    
        if error != nil {
            print("Failed to load image for url: \(urlString), error: \(error?.description)")
            return
        }
    
        guard let httpResponse = response as? NSHTTPURLResponse else {
            print("Not an NSHTTPURLResponse from loading url: \(urlString)")
            return
        }
    
        if httpResponse.statusCode != 200 {
            print("Bad response statusCode: \(httpResponse.statusCode) while loading url: \(urlString)")
            return
        }
    
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.myImageView.image = UIImage(data: data!)
        })
    
        }.resume()
    

    【讨论】:

    • sendAsynchronousRequest:queue:completionHandler: 在 iOS 9 中已弃用,现在使用 [NSURLSession dataTaskWithRequest:completionHandler:]
    • 很棒的答案非常感谢。我唯一要说的是guard let url = NSURL(string: urlString) else {return} 然后let request = NSURLRequest(URL: url) 只是因为网址字符串格式错误以避免崩溃。
    【解决方案2】:
    NSString *ImageURL = @"YourURLHere";
    NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
    imageView.image = [UIImage imageWithData:imageData];
    

    【讨论】:

    • 这是同步的,在检索图像时会锁定主线程。一个非常糟糕的主意。
    • 如果你有长数据,请使用 HJCache(可以在 github 中找到)。避免 UI 冻结。
    • 您可以轻松地使其异步。但它的本质是最优雅的。
    • 由开发人员决定同步访问是否足够好 - 此外,UIImage 的创建和从 URL 同步加载远程文件 - 当然可以包装在dispatch_async、NSOperation、后台线程或任何其他用于并发、缓存或其他的技术。您必须在主线程上做的唯一一件事就是将图像附加到 imageView。所以答案是完全可行和正确的,并且没有直接的性能影响
    【解决方案3】:

    可以从 URL 加载 NSData 并将其转换为图像并将其粘贴在图像视图中,但这是一个非常糟糕的主意,因为它涉及在主线程上执行同步 URL 下载。这将锁定 UI,如果图像下载速度不快,可能会导致用户认为您的应用已崩溃。

    编辑:澄清一下,在我看来,最初的问题就像发帖人想说的那样

    imageView.image = [UIImage imageWithContentsOfURL:theURL];
    

    因此我的回答。可以通过 NSData 来做同样的事情,但这是个坏主意。相反,应该使用 NSURLConnection 异步下载图像,并且只有在完全下载后才能将其转换为 UIImage 并分配给图像视图。

    【讨论】:

    • +1 正如你所说,这绝对是个坏主意。也就是说,您可以使用占位符图像,然后在后台触发 NSURLConnection。
    • 好的。多线程呢?有没有其他方法来设计一个动态应用程序,我的想法是在一个 plist 中阅读,并使用这个列表中的链接来例如读取图像并显示它。我不想每次网站更新时都更新应用程序。
    • @alJaree 正如我建议的那样,您可以使用占位符图像并通过 NSURLConnection 异步加载“当前”图像。有一个很好的例子说明如何在 URL Loading System Programming Guide 中使用 NSURLConnection
    • 您还应该考虑缓存您下载的图像,以便在启动下载之前首先检查您是否已经拥有它(认为图像本身不会与服务器中的图像发生变化)
    • [UIImage imageWithContentsOfURL:theURL];方法现在不可用。
    【解决方案4】:

    我正在使用https://github.com/rs/SDWebImage,这是一个设计精美的库,它可以选择放置占位符图像,无论是存储到内存还是磁盘缓存图像或使用独立于UIImageView的下载器。

    我试图自己做,但图书馆消除了所有的痛苦。

    您需要做的就是为您的案例编写以下代码:

    #import "UIImageView+WebCache.h"
    
    [imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
    

    对我来说就像一个魅力。

    【讨论】:

    • 我总是更喜欢编写自己的代码,但仅仅 5 分钟的工作,我从这个库中获得的流畅性和速度令人印象深刻。详细的安装说明也有帮助。
    【解决方案5】:

    如果您想在 ImageView 中显示来自 Url 的图像,并且还想将此图像保存在缓存中以优化服务器交互,这将有助于您只需将您的 imageView 对象和字符串 Url 传递给此函数

    -(void)downloadingServerImageFromUrl:(UIImageView*)imgView AndUrl:(NSString*)strUrl{
    
    
    strUrl = [strUrl encodeUrl];
    
    NSString* theFileName = [NSString stringWithFormat:@"%@.png",[[strUrl lastPathComponent] stringByDeletingPathExtension]];
    
    
    NSFileManager *fileManager =[NSFileManager defaultManager];
    NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"tmp/%@",theFileName]];
    
    
    
    imgView.backgroundColor = [UIColor darkGrayColor];
    UIActivityIndicatorView *actView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
    [imgView addSubview:actView];
    [actView startAnimating];
    CGSize boundsSize = imgView.bounds.size;
    CGRect frameToCenter = actView.frame;
    // center horizontally
    if (frameToCenter.size.width < boundsSize.width)
        frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) / 2;
    else
        frameToCenter.origin.x = 0;
    
    // center vertically
    if (frameToCenter.size.height < boundsSize.height)
        frameToCenter.origin.y = (boundsSize.height - frameToCenter.size.height) / 2;
    else
        frameToCenter.origin.y = 0;
    
    actView.frame = frameToCenter;
    
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
    
        NSData *dataFromFile = nil;
        NSData *dataFromUrl = nil;
    
        dataFromFile = [fileManager contentsAtPath:fileName];
        if(dataFromFile==nil){
            dataFromUrl=[[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:strUrl]] autorelease];                      
        }
    
        dispatch_sync(dispatch_get_main_queue(), ^{
    
            if(dataFromFile!=nil){
                imgView.image = [UIImage imageWithData:dataFromFile];
            }else if(dataFromUrl!=nil){
                imgView.image = [UIImage imageWithData:dataFromUrl];  
                NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"tmp/%@",theFileName]];
    
                BOOL filecreationSuccess = [fileManager createFileAtPath:fileName contents:dataFromUrl attributes:nil];       
                if(filecreationSuccess == NO){
                    NSLog(@"Failed to create the html file");
                }
    
            }else{
                imgView.image = [UIImage imageNamed:@"NO_Image.png"];  
            }
            [actView removeFromSuperview];
            [actView release];
            [imgView setBackgroundColor:[UIColor clearColor]];
        });
    });
    
    
    }
    

    【讨论】:

      【解决方案6】:

      这是最佳答案的更新答案,因为 imageWithContentsOfURL 不再是 UIImage 的方法。你必须使用 CIImage:

      NSURL *url = [NSURL URLWithString:@"http://url_goes_here.com/logo.png"];
      imageView.image = [UIImage imageWithCIImage:[CIImage imageWithContentsOfURL:url]];
      

      【讨论】:

      • 这是我最喜欢的,虽然我会分成 3 行,以允许将 CIImage 的创建(以及从 URL 同步加载远程文件)推迟到一些后台任务。
      【解决方案7】:

      不幸的是,此功能在撰写本文时不可用...相反,您必须自己实现该功能:

      1. 下载图片数据
      2. 将其保存或缓存在某处(数据库或文件系统),然后
      3. 将 UIImaveView 设置为保存的结构

      幸运的是,由于 Apple 提供了 an example that does exactly that 作为其代码示例的一部分,因此您不必为上述功能而伤脑筋。

      按照代码进行操作,我相信您将能够满足您的需求。

      【讨论】:

      • 谢谢。它提到了RSS。这个例子不只是读入一个 RSS 流并抓取图像吗?我已经在应用程序中拥有此功能,我现在正尝试从网站的 url 读取数据结构。在我的应用程序中使用这个结构来获取图像的数量,然后获取每个图像的 url,并根据 plist 中对应的编号,用图像设置特定的 UIImageView,这样我可以动态更新应用程序并替换图片。
      • 这只是示例应用程序功能的一部分,但您要注意的是它获取图像的 url 并获取它们的部分(这就是 IconDownloader 类的用途)。 .. 这个示例更进一步,因为它还向您展示了如何以高效的方式从 tableview 使用此类。
      【解决方案8】:

      EGOImageLoading

      EGOImageView* imageView = [[EGOImageView alloc] initWithPlaceholderImage:[UIImage imageNamed:@"placeholder.png"]];
      imageView.frame = CGRectMake(0.0f, 0.0f, 36.0f, 36.0f);
      
      //show the placeholder image instantly
      [self.anyView addSubview:imageView];
      [imageView release] //if you want
      
      //load the image from url asynchronously with caching automagically
      imageView.imageURL = [NSURL URLWithString:photoURL]; 
      

      如果你想要更多,有一个委托来处理加载后的操作

      @protocol EGOImageViewDelegate<NSObject>
      @optional
      - (void)imageViewLoadedImage:(EGOImageView*)imageView;
      - (void)imageViewFailedToLoadImage:(EGOImageView*)imageView error:(NSError*)error;
      @end
      

      【讨论】:

      • 有什么意义? UIImageView 原生支持占位图片?
      • @MottiShneor 请显示UIImageView如何支持它的代码?
      【解决方案9】:

      另一个选项是 Three20 库中的 TTImageView,它处理图像的异步加载。控制效果很好。然而,缺点是您必须面对安装 Three20 的噩梦(这几乎不可能完全移除)。

      【讨论】:

        【解决方案10】:

        使用AFNetworking 类别UIImageView+AFNetworking.h

         #import "UIImageView+AFNetworking.h
        
        
        [profileImageView setImageWithURL:[NSURL URLWithString:photoURL] placeholderImage:[UIImage imageNamed:@"placeholder"]];
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-01-10
          • 2023-03-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-19
          • 1970-01-01
          相关资源
          最近更新 更多