iOS 文件导入(OTG)开发问题随记2

    在文章iOS 文件导入(OTG)开发问题随记1中记录了开发OTG的一些基本的问题,接下来记录一下OTG开发步骤以及遇到的问题。

    我在开发文件导入(OTG)中主要分成了两个部分。1.从U盘拷贝文件到手机,2.将拷贝出来的文件进行编解码。

1.从U盘拷贝文件到手机。

    拷贝文件一开始使用的是系统提供的FileManager类中的 copyItem(atPath srcPath:String, toPath dstPath:String)方法。在应用之间互相拷贝时使用这个方法没有问题,但是如果是从U盘到手机,这个方法就不适用了,主要有以下几个问题:

1).拷贝过程中无法暂停,针对大文件拷贝,拷贝暂停是刚需。

2).报错信息很委婉,U盘拔出这个异常是需要重点考虑的,但是针对这块的报错信息不明确,而且报错信息需要从FileManagerDelegate中去捞,信息不明确,

3).大量数据会先缓存到内存中,然后进行拷贝,导致U盘拔出之类的error不及时。这个是我猜测的,现象是在拷贝过程中,把U盘拔出,这时并没有及时进入到error的代理中,过了一段时间才进入error的delegate中,所以猜测是缓存到内存中的数据并没有拷贝完,在拷贝完成之后,再次去U盘中读取数据读取不到时才会报错。无论原因是什么,导致的问题就是error的delegate没有及时执行。

4).在文件拷贝过程中,无任何反馈,如果想要计算进度是没办法做到的。

    考虑到以上几个问题,FileManager中的拷贝方法就行不通了,还得自己去实现文件拷贝的功能。自己实现文件拷贝的功能就是从一个文件中固定读多少数据,然后将读取到的数据拷贝到指定的目录。核心逻辑就是readDataOfLength,然后writeData。但是这一套还是无法解决U盘拔出的异常,当时没管这个,先实现了这一套,在实现这套之后,上面的问题1,4都得到了解决。但是如果在读取数据过程中将U盘拔出还是会出crash,在这里我踩了很多坑,比如判断文件读取路径是否存在,路径是否有效,路径是否有读取权限等等。但是最后都失败了,然后无意中进入NSFileHandle中看了一下readDataOfLength方法,豁然开朗,这几个方法写着都已经废弃了,建议我们用替代方法去实现功能,比如

- (NSData *)readDataOfLength:(NSUInteger)length

 API_DEPRECATED_WITH_REPLACEMENT("readDataUpToLength:error:",

 macos(10.0,API_TO_BE_DEPRECATED), ios(2.0,API_TO_BE_DEPRECATED),

watchos(2.0,API_TO_BE_DEPRECATED), tvos(9.0,API_TO_BE_DEPRECATED));

readDataOfLength有了替代方法readDataUpToLength:error:,然后我看了一下readDataUpToLength:error:,

- (nullableNSData*)readDataUpToLength:(NSUInteger)lengtherror:(outNSError**)error

    API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))NS_REFINED_FOR_SWIFT;

上述方法是从13.0开始支持的,然后iOS的OTG也是从iOS13开始支持的,然后我猜测就是为了考虑到外接盘符的插拔,然后更新了这个方法提供使用。我将App中的相关方法都更换成了iOS13支持的带error的方法,然后所有问题都解决了,在拷贝过程中,如果盘符拔出,则会报error,告知文件读取路径不存在,错误提示高效又明朗。一下子解决了上述的2,3问题。所以从U盘拷贝文件到手机基本就没啥问题了。

2.将拷贝出来的文件进行编解码。

    这部分的功能主要是从本地文件读取数据然后进行一段一段的编解码,这部分的逻辑很正常,唯一要注意的点是,在while循环中进行读取解码时,会导致CPU暴增,一度会增加到100%,在文件比较大时,最终App会被看门狗杀掉。所以在while循环读取中,需要适当sleep来控制一下CPU。

    整个OTG的主线问题就是以上几个问题,但是在开发过程中,真正头疼的都是一些支线问题,支线问题是根据业务的需求而不同的,我主要碰到以下几个问题:

1).有关url的操作权限问题。

2).有关Realm的数据存储问题。

     针对问题1),因为在documentPicker(_controller:UIDocumentPickerViewController, didPickDocumentsAt urls: [URL])代理中,会返回选中文件的url路径,而且在iOS11以上开始支持多选,所以返回的数据是一个数组。而且在上一篇文章中说过,OTG形式的文件导入,只能采用UIDocumentPickerMode为open。在这种模式下,对文件路径的使用url都需要通过startAccessingSecurityScopedResource()请求权限,在执行完成之后,需要通过stopAccessingSecurityScopedResource()关闭权限。大致代码如下:

        for url in urls {

            let securitySucceeded = url.startAccessingSecurityScopedResource()

            if securitySucceeded {

                AudioFileManager.sharedInstance.importAudioFiles(urls: [url])

            }

            url.stopAccessingSecurityScopedResource()

        }

    如果选中了多个url,需求肯定希望是所有选中的url先展示出来,之后再一个一个处理url,进行导入,编解码。我一开始的实现是这样的,所有选中的url都会作为一条本地的记录,保存到Realm中,然后UI根据本地存储的Realm中的数据进行展示,最后再处理每个url。当时我先把url存入Realm,到合适的时候将它们取出来,通过请求关闭权限对其进行操作。但是在这个过程中发现,url转为String存入数据库中,再取出来转化为URL对其进行操作时,startAccessingSecurityScopedResource()始终获取不到url的使用权,这部分的原理我没有想通,其实那时候我应该多测试一下,在URL类下面有很多有关权限的方法,但是当时因为时间问题我没有尝试,我采用了一个最低级的方法,我把所有选中的url都保存在内存中,要用的时候取对应的url,这样就是可以获取使用权限,目前就是这种方案实现的,应该有更好的实现方案。

    针对问题2),因为项目中有很多本地文件需要处理,为了方便,采用了Realm数据库,可能是Realm使用的还是不太熟,过程中遇到很多坑,多线程使用,数据得不到及时更新,在一边拷贝数据,一边更新数据库时,会导致拷贝的数据保存到数据库中。我在主线程中添加对应的url数据,但是在子线程中怎么都拿不到这个新添加的数据,后来我在每次获取数据库数据之前,都将Realm强制refresh,这样确实解决了问题,但是也带来了新的问题。我需要在一边将文件数据拷贝到指定目录之后,计算出拷贝的文件比例存入Realm,但是因为上面的refresh的原因,导致拷贝的数据也会存入Realm中变成垃圾数据,如果文件很大,就会导致Realm中的数据也很多,最终会crash。针对这个问题,我先是在Realm的初始化中的shouldCompactOnLaunch block中设置使用数据大于10M就return true,这意味着数据库会被压缩,这样确实解决了启动之前Realm就很大的问题,但是我的那种场景是使用过程中会导致垃圾数据很多,这种情况是不会主动压缩的,那这个问题还是解决不了。当时为了快速解决这个问题,我把进度拿出来单独处理了。。。

    在实现U盘文件导入到iphone的主要步骤和主要问题就是上面所述,如果还想起其他问题会及时更新。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容