使用OC加载图片的两种方式及其区别

  在iOS中加载图片的方式有多种,通过OC的方式主要有imageName:和imageWithContentsOfFile:两种。这两种方式如何使用,以及他们之间的区别是什么呢?下面通过两个小示例来详细讲解。

一、imageNamed:和imageWithContentsOfFile:的使用

  1、imageNamed:
  新建一个工程,将准备好的图片拖入项目中Assets.xcassets文件夹中,具体步骤如下图所示:


Snip20160720_33.png

  来到ViewController.m文件,在viewDidLoad方法中加载图片:

    UIImageView *imageView = [[UIImageView alloc] init];  // 创建imageView对象
    imageView.frame = CGRectMake(0, 0, 265, 395);  // 设置imageView的尺寸
    imageView.center = self.view.center;  // 让图片在中间位置显示
    imageView.image = [UIImage imageNamed:@"0009"];  // 加载图片
    [self.view addSubview:imageView];  // 显示图片

  显示结果如下:


Snip20160720_36.png

  2、imageContentsOfFile:
  与上面一样,新建一个工程,然后再将图片资源拖入到项目中。与上面不一样的是,这次图片资源不是拖入Assets.xcassets文件夹中,而是拖入到Supporting Files文件夹中,原因后面再做解释。详细步骤如下图所示:


Snip20160720_38.png

  需要注意的是,在拖入图片的过程中Xcode会弹出一个"Choose options for adding these files"的提示框,一般按照上图所示选择默认勾选项就可以了(其中Create groups表示在项目中创建虚拟文件夹,而Create folder references表示创建实际文件夹),如果不勾选的话,会出问题。图片资源拖入完成以后效果如下图所示:


Snip20160720_41.png

  通过imageWithContentOfFile:的方式加载图片资源的代码如下:

    UIImageView *imageView = [[UIImageView alloc] init];  // 创建imageView对象
    imageView.frame = CGRectMake(0, 0, 265, 395);  // 设置imageView的尺寸
    imageView.center = self.view.center;  // 让图片在中间位置显示
    NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"0010" ofType:@"jpg"];  // 获取图片资源所在路径
    imageView.image = [UIImage imageWithContentsOfFile:imagePath];  // 加载图片
    [self.view addSubview:imageView];  // 显示图片

  运行结果如下图所示:


Snip20160720_40.png

二、imageNamed:和imageWithContentsOfFile:的区别

  1、打包方式上的不同
  项目完成以后,所有的图片资源会被一起打包成ipa文件发布到AppStore,拖入Assets.xcassets文件夹中的图片最后会被打包成一个Assets.car文件,我们不能根据路径读取图片。而拖入Supporting Files文件夹中的图片可以根据路径读取。另外,从某种程度上讲,拖入Assets.xcassets文件夹中的图片因为被打包成了Assets.car文件,可以得到一定程度上的保护,以防止盗图(之所以说是一定程度,是因为我们依然可以通过其他手段解压相关图片)。而拖入Supporting Files文件夹中的图片则直接暴露在外面。可以通过下面一系列图片来验证我们的一些结论(验证方法见:如何快速定位模拟器中的沙盒存放路径):


Snip20160720_43.png

  点击"Bundle"——"Application",然后找到当前项目:


Snip20160720_44.png

  右击当前项目,选择"显示包内容",可以看到我们拖入到Assets.xcassets文件夹中名称为0009.jpg的图片没有了,其实他被打包到Assets.car文件夹里面去了。而拖入到Supporting Files文件夹中名称为0010.jpg的图片可以直接查看:


Snip20160720_45.png

  我们可以借助iOS images Extractor插件来验证名称为0009.jpg的图片是否被打包到Assets.car文件中:


Snip20160720_47.png

  2、出于内存和程序性能方面的考虑
  除了像上面提到的打包方式上的差别之外,还有另外一个重要的区别,就是从内存和程序性能方面的考虑。为了说明这个问题,我们需要借助另外一个小程序来作进一步的说明。
  新建一个工程,分两步来讨论通过不同的方式加载图片所表现出来的程序性能的问题。
  通过imageNamed:方法来加载图片。首先将准备好的素材拖入到项目中的Assets.xcassets文件夹当中,然后通过imageNamed:方法来加载:


Snip20160720_48.png

  加载图片的代码如下:

// 抽取加载图片重复的代码
- (NSArray *)loadImagesWithImagePrefixName:(NSString *)prefixName count:(int)count  {
    NSMutableArray<UIImage *> *images = [NSMutableArray array];  // 创建一个可变数组,用于装载图片
    for (int i = 0; i < count; i++) {
        NSString *imageName = [NSString stringWithFormat:@"%@_%d", prefixName, i + 1];  // 获取图片的名称
        UIImage *image = [UIImage imageNamed:imageName];  // 加载图片
        [images addObject:image];  // 将图片添加到可变数组中
    }
    return images;  // 返回数组
}

  运行程序来查看内存使用情况:


stand.gif

  我们可以看到站立情况下,内存始终是29M左右。点击小招以后内存上升到35.8M,点击大招以后,内存上升到57.2M。这主要是因为每点击一次不同的招数,系统就会加载更多的图片,因此造成内存使用量增加。


小招.gif

大招.gif

  重点在于点击停止按钮以后。点击停止按钮所执行的代码如下:

// 游戏结束
- (IBAction)gameOver {
    self.standImages = nil;
    self.smallImages = nil;
    self.bigImages = nil;
    self.imageView.animationImages = nil;
}

  理论上讲,我们点击停止按钮以后,保存在数组中的图片资源被清空,内存使用量应该下降,但事实上却并没有:


Snip20160720_53.png

  产生上述问题的主要原因是,通过imageNamed:方法加载的图片,其图片在使用完成后,并不会立即被释放掉,具体释放时间由系统决定。因此,这种加载方法,适用于图片小、数量少,且经常使用的图片处理场合

  通过imageWithContentsOfFile:方法来加载图片。和上面一样,将准备好的素材拖入到项目中,不过这次不是拖入到Assets.xcassets文件夹,而是直接拖入到Supporting Files文件夹中,具体情况如下图所示:


Snip20160720_54.png

  修改加载图片的代码:

// 抽取加载图片重复的代码
- (NSArray *)loadImagesWithImagePrefixName:(NSString *)prefixName count:(int)count  {
    NSMutableArray<UIImage *> *images = [NSMutableArray array];  // 创建一个可变数组,用于装载图片
    for (int i = 0; i < count; i++) {
        NSString *imageName = [NSString stringWithFormat:@"%@_%d", prefixName, i + 1];  // 获取图片的名称
        NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"png"];  // 获取图片在资源包中的路径
        UIImage *image = [UIImage imageWithContentsOfFile:imagePath];  // 加载图片
        [images addObject:image];  // 将图片添加到可变数组中
    }
    return images;  // 返回数组
}

  修改完成以后运行程序,点击小招、大招,程序运行时占用内存的情况与通过imageNamed:方式加载图片运行时的情况是一样的。但是,当我们点击停止按钮以后,发现内存使用量又降为29.4M左右了:


停止.gif

  这个主要是因为,通过imageWithContentsOfFile:方法加载的图片可以快速的手动释放。
  通过这个示例,我们基本上可以总结出imageNamed:和imageWithContentsOfFile:这两个方法的使用场合:

1、imageNamed:方法适用于经常使用,并且图片小、数量少的场合,方便快速加载;
2、imageWithContentsOfFile:方法适用于图片比较大,并且图片数量非常多的场合,此时需要考虑程序的性能。

  完整的代码:https://github.com/enricashi/loadImages

文/Enrica(简书作者)
原文链接:http://www.jianshu.com/p/42358cebd2bc
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您可以使用CFNetwork框架来实现FTP上传图片。下面是一个简单的示例代码: ``` - (void)uploadImageToFTP:(UIImage *)image { // FTP服务器地址、用户名、密码 NSString *ftpUrl = @"ftp://ftp.example.com"; NSString *userName = @"username"; NSString *password = @"password"; // 生成图片的NSData NSData *imageData = UIImageJPEGRepresentation(image, 1.0); // 生成文件名 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyyMMddHHmmss"; NSString *fileName = [NSString stringWithFormat:@"%@.jpg", [formatter stringFromDate:[NSDate date]]]; // 生成FTP文件路径 NSString *ftpFilePath = [NSString stringWithFormat:@"%@/%@", ftpUrl, fileName]; // 生成FTP URL CFURLRef ftpURL = CFURLCreateWithString(NULL, (__bridge CFStringRef)ftpFilePath, NULL); // 生成FTP Write Stream CFWriteStreamRef writeStream = CFWriteStreamCreateWithFTPURL(NULL, ftpURL); // 设置FTP用户名和密码 CFWriteStreamSetProperty(writeStream, kCFStreamPropertyFTPUserName, (__bridge CFStringRef)userName); CFWriteStreamSetProperty(writeStream, kCFStreamPropertyFTPPassword, (__bridge CFStringRef)password); // 打开FTP Write Stream if (CFWriteStreamOpen(writeStream)) { // 写入数据 const uint8_t *buffer = [imageData bytes]; CFIndex bytesWritten = CFWriteStreamWrite(writeStream, buffer, [imageData length]); // 关闭FTP Write Stream CFWriteStreamClose(writeStream); if (bytesWritten == [imageData length]) { NSLog(@"FTP上传成功"); } else { NSLog(@"FTP上传失败"); } } else { NSLog(@"FTP连接失败"); } // 释放资源 CFRelease(writeStream); CFRelease(ftpURL); } ``` 在上面的代码中,我们首先定义了FTP服务器地址、用户名和密码,然后生成了要上传的图片的NSData、文件名、FTP文件路径和FTP URL。接着,我们使用CFWriteStreamCreateWithFTPURL函数创建了FTP Write Stream,并设置了FTP用户名和密码。然后,我们打开FTP Write Stream,并将图片数据写入到FTP服务器上。最后,我们检查数据是否写入成功,并释放资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值