iOS 的 UITextView 显示含有网络图片的 NSAttributedString 时,怎么样接管网络图片的下载过程?

2014-11-26 18:59:00 +08:00
 q84629462
NSString *html = @"<img src=\"http://cdn.v2ex.com/site/logo@2x.png\"/>";
NSDictionary *options = @{NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType};
NSAttributedString *string = [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUnicodeStringEncoding] options:options documentAttributes:nil error:&error];
//textView是UITextView
[text setAttributedText:string];
想在上面这一个过程中,实现:
把html中的img替换成小的缩略图显示,并使用TMCache缓存缩略图,在UITextView中点击缩略图后,显示原图。
搜索了两三天,依然找不到图片的下载是在NSAttributedString/UITextView这两个玩意的哪个方法里,倒是实现了点击后识别是否图片。
31971 次点击
所在节点    iDev
80 条回复
jox
2014-12-21 15:20:43 +08:00
我觉得你还是没有整明白text kit到底该怎么用,text kit是一个排版引擎,不是专门用来给text view渲染文字的。你问的这个问题很简单,text kit排版完成之后就可以得到版式相关的数据了,跟排版后的文字是否已经被渲染过没有关系。

你好好看看文档啊,不能指望网上的某个陌生人(v2ex上一个id为jox的家伙)每次在你遇到问题的时候都蹦出来回答你的问题吧?如果我半年才上一次或者对v2ex厌倦了不再上线了怎么办?你的这个问题看看文档很容易就能解决,首先把text kit的核心对象创建好并彼此连接,然后使用ensure....系列的方法强制layout manager进行排版,layout manager在这个过程中会生成字形,然后进行排版,排版完成之后使用boundingRect。。。。那个方法就可以得到某个字形的位置和尺寸。

好好看看文档,顺便了解一下文字的排版过程,相信对你理解text kit的用法会有帮助。不要再@我了,有问题直接去stackoverflow上去问,那个网站我每天都会上线,碰到我了解的问题我会回答的,为了在选择答案的时候的客观性,也别问我的stackoverflow的id了,v2ex这个网站不适合用来提问与回答技术类的问题。
OctWu
2014-12-23 22:58:15 +08:00
@jox cool,在做富文本输出的时候搜到了这篇文章,帮助很大。虽然可能v2ex不适用做提问,我还是很好奇,因为我在parse html然后用text kit进行了排版后。遇到了两个问题
1.我们的图片大小不统一,这样我就需要来给这个根据NSTextAttachment的生成的attributedString加一个居中的段落属性,但是相对应的是这个图片就必须要单独一个段落了,是否有更好的方法呢。
2.因为我现在的应用的html内容有时候会出现大量的图片,内存还是比较吃紧的。不知道你有没有遇到这样的问题
jox
2014-12-23 23:09:48 +08:00
@OctWu

1.图片我的处理方法是创建nstextattachment的时候配置bounds属性,给一个非常大的width,比屏幕最大宽度还大,这样text kit就会把绑定图片的那个特殊字符单独放一行,排版完成之后使用layout manager找到图片的位置,然后再设置图片的frame来进行手动排版。之所以要这么做是因为parse html之后得到的只是一个url,在图片下载下来之前不知道图片到底有多大,索性就所有图片使用统一的缩略图尺寸,如果用户想要看一个图片的细节,点击图片之后会使用整个屏幕来单独显示图片,这时候就可以使用图片的原始尺寸。

2. 使用NSCache缓存解压缩过的图片,内存不够的时候NSCache会释放图片对象,只保留图片的url,我使用nsurlsession,这个会做缓存,图片数据会保存在硬盘上,用到的时候如果NSCache里找不到解压缩过的图片,那就重新下载图片,因为有缓存,所以不会从源再次下载,只需要从硬盘读取图片数据然后重新解压缩就可以了,实际效果挺不错的,Image I/O的性能非常出众,图片是很占内存的,必须使用缩略图,只有在需要的时候才会单独显示一张大的图片
OctWu
2014-12-24 08:33:33 +08:00
@jox

关于第一点我的理解,你是通过NSTextAttachment在布局的时候,通过bounds的设定占了一段空白位置。然后再去粘贴UIImageView?如果是这样,因为我们的图片比例非常的奇怪(1 :1, 1: 7等等)所以设置一个比较通用的bounds还是微难的。可能是我没有找到,有没有很好的方法单独来重新绘制某个NSTextAttachment?现在我都是通过storege replaceAttributedString来重绘
jox
2014-12-24 09:31:37 +08:00
@OctWu 我只用text kit帮我留空白 至于图片是用imageview 还是自己画是无所谓的 我不用text kit画图片 因为那样不好控制 我只用text kit画文字和排版 你如果事先知道图片的尺寸 排版就很容易了
OctWu
2014-12-25 10:28:40 +08:00
唔,尺寸不可控。不过都是独立一行.剧中。
OctWu
2014-12-26 00:05:49 +08:00
@jox 关于内容大小这个问题,用sizeThatFits似乎不需要考虑到黑魔法的问题。当然你必须保证高宽其中一项是可知的
jox
2014-12-26 00:52:02 +08:00
@OctWu sizeThatFits?我没用到这个。黑魔法指的是?图片的高度不能弄得太高,实际上图片的尺寸要尽可能的小,因为图片都是独占一行,如果图片的高度比较高,那么整个需要渲染的像素数量就会被拉高很多,内存,CPU,GPU的压力都会升高,你算一下就知道了,iPhone 6的分辨率 750 x 1334,假如一次性需要渲染两屏幕,总共需要渲染的像素数就是750 x 1334 x 2 = 2001000,每个像素需要4bytes,要想渲染这么多像素就需要2001000 x 4 = 8004000 bytes = 7.6MB,有的时候我的应用需要渲染超过10000 points的图片,一下就要用到将近50MB的内存,多个线程同时画的图片都这么大的话内存直接就爆掉了,就拿我们现在在的这个帖子来说,如果使用iOS 7新出的text style,一般字体的高度是17 points左右,上面那几个稍微长点的帖子很容易就能占据两三屏幕,再夹杂一些图片,就更长了。我所有的图片都是100 x 100 points,iPhone 6 Plus以外的设备就是200 x 200 pixels,iPhone 6 Plus是300*0.84 x 300*0.84 pixels,不管原尺寸多大,都是等比例缩小的,看着也能大概看出来图片内容是啥,用户点击图片能看到缩放到屏幕尺寸的图片,还可以双击缩放某一个区域,两个手指头pinch进行缩放,旋转之类的。很多需要图文混排的应用几乎都是这么做的,腾讯的微信,百度的百度贴吧,都只显示固定尺寸的缩略图,你可以参考一下。
OctWu
2014-12-26 09:23:18 +08:00
@jox 多线程同时画图片?textView本身是scrollView的子类。屏幕外的东西是不用绘制的。你说的内存的问题。是不是你却并没有根据分辨率重新切割图片而是直接交给imagview。这样渲染的时候CG会消耗非常大。还有就是图片本身的大小也很关键。50如果是真机,应该去检查下内存使用在哪了。关于缩略图是这样,我们的图片是需要用户可以看清的。但是比例千奇百怪囧rz,所以没有使用这种方案。
OctWu
2014-12-26 09:29:59 +08:00
@jox 你有统计过用来占位的NSTextAttchment对内存的压力么。其实对于显示这点来说。完全可以设置抗拒范围。而不用占位。其实我再尝试使用tableview配合来显示,因为image已经固定了格式。还可以重用。当然textview也是OK的
jox
2014-12-26 09:31:10 +08:00
@OctWu 我没用textview 另外textview应该也是一次性把所有文字都画出来的 你在主线程丢给textview一大段文字看看主线程会不会阻塞就知道了 大图片就是要那么多内存 你用VM tracker就能看到了 xcode里只显示heap上的内存占用 那不是真正的内存占用 Xcode里显示占用内存不到10MB 实际上却可能占用将近100MB 图片占用的内存没有被计算进去
OctWu
2014-12-26 17:12:59 +08:00
@jox 你提到了textView是一次性绘制,我就尝试替换为了tableView(原因也是因为图片都是单独一行并且居中),真机测试结果消耗内存从30 ~ 55降低到了稳定的9 ~ 17。 很感谢你上面的回答解决了我很多的困惑。
jox
2014-12-26 17:26:42 +08:00
@OctWu 谢谢你感谢我 :)

你怎么看的内存占用?xcode里面Debug navigator里的内存占用不是真正的内存占用,你需要使用VM Tracker才能得到真正的内存占用。内存占用方面可以看看WWDC 2012里的关于内存的那个session,名字我忘记了,那里提到了如何优化应用的内存占用。
OctWu
2014-12-26 21:28:12 +08:00
@jox 哈,那是否提供一个联系方式呢。调试比较迷糊。哈
jox
2014-12-26 21:43:44 +08:00
@OctWu 可以给我发邮件,交流起来比较方便,其实我也是刚开始iOS的开发没多久,也是新手,哈。

这个: http://weibo.com/u/5341809257 这是我用来做图床的新浪微博,我刚随便发了个微博,你可以去给我发私信,我可以把我的邮箱地址告诉你,v2ex网站不能发私信,我不想把我的邮箱发到公网上
OctWu
2014-12-26 23:06:55 +08:00
@jox 已发,请check
WildCat
2015-09-19 22:16:23 +08:00
楼主还在么?这个帖子的问题最后解决得如何了?
1027963459
2015-10-05 08:50:42 +08:00
我想做的时类似记事本那种 用 textView 做的 在输入的事后在光标处插入图片 我用的是 NSTextAttachment 插入的 但是之后保存到本地时 在当前文本上 找不到图片 也没法点击图片触发事件 图片应该只占了一个字符的空间 插入图片后 整体字符串长度值增加了 1 各位大神有木有解决办法或者好方法啊
ysghome
2016-09-26 11:53:51 +08:00
@jox 有 dome 吗,最近一直在弄这个东西,进展缓慢啊。
wojing
2016-11-27 19:43:04 +08:00
@q84629462 ,
@OctWu 可有类似的小 demo ,主要是通过解析的 dom 树之后,文本和附件的创建,已经最终计算富文本的高度

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/149498

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX