通過UIDocumentInteractionController預(yù)覽和分享"史蒂夫?喬布斯傳"

前言

朋友分享推薦給我一本PDF格式的史蒂夫?喬布斯傳,閱讀了幾篇,很受感觸哀卫,于是想把他分享給大家欣賞閱讀。早起閑來無事撬槽,正好就接著寫篇文章來分享一下此改!我在“iOS實(shí)現(xiàn)App之間的內(nèi)容分享”這篇文章中詳細(xì)講解了通過注冊(cè)UTI的方式讓我們的App支持分享,也簡單地說了一下App內(nèi)部怎么處理分享侄柔。同時(shí)共啃,我也指出了在iOS系統(tǒng)跨App分享內(nèi)容的幾種常用技術(shù),比如URL Scheme,AirDrop, UIDocumentInteractionController,UIActivityViewController這幾種暂题。這一篇文章移剪,我們來談一下最基礎(chǔ)的原始方法,怎么通過使用UIDocumentInteractionController來預(yù)覽薪者、操作和分享史蒂夫?喬布斯傳纵苛。

簡介

從iOS SDK的API文檔中,我們可以找到UIDocumentInteractionController的聲明:

NS_CLASS_AVAILABLE_IOS(3_2) __TVOS_PROHIBITED @interface UIDocumentInteractionController : NSObject <UIActionSheetDelegate>


由此聲明我們可以得知言津,`UIDocumentInteractionController`是從iOS 3.2的SDK開始支持的攻人,它是直接繼承的`NSObject`,而不是我們想象的`UIViewController`悬槽,因此我們需要使用`UIDocumentInteractionController`提供的方法來展示它怀吻,而且我們還可以看出它是不能在Apple TV 的開發(fā)中使用的。遍觀`UIDocumentInteractionController`的屬性和方法可以看出初婆,`UIDocumentInteractionController`主要給我們提供了三種用途蓬坡,我會(huì)在下面的內(nèi)容中逐條的講解`UIDocumentInteraction`的每一種用途的具體使用:
>1. 展示一個(gè)可以操作我們分享的文檔類型的第三方App列表
2. 在第一條展示列表的基礎(chǔ)上添加額外的操作,比如`復(fù)制`烟逊,`打印`渣窜,`預(yù)覽`铺根,`保存`等宪躯。
3. 結(jié)合`Quick Look`框架直接展示文檔內(nèi)容

#準(zhǔn)備階段
首先我創(chuàng)建了一個(gè)新的應(yīng)用方便演示和截圖,我把它命名為`ZSDocumentInteractionTest`位迂,然后拖入PDF格式的`史蒂夫?喬布斯傳`到`ZSDocumentInteractionTest`項(xiàng)目的bundle中访雪。然后在`Storyboard`的`ViewController`中添加了一個(gè)Button作為`UIDocumentInteractionController`的觸發(fā)操作(這些操作都比較簡單详瑞,就不在這里用圖展示啦)。運(yùn)行程序臣缀,我們就可以看到Button啦坝橡,截圖如下。然后我們就可以在Button的觸發(fā)方法中精置,操作`UIDocumentInteractionController`來顯示或者分享我們的`史蒂夫?喬布斯傳`啦计寇,具體的應(yīng)用詳情可以參考GitHub上的Demo:[ZSDocumentInteractionTest](https://github.com/SeraZheng/ZSDocumentInteractionTest)。

![在ViewController的視圖 中顯示Button](http://upload-images.jianshu.io/upload_images/1216322-9fac2efc2d9a6bc4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

#初始化
不管我們使用哪種`UIDocumentInteractionController`的展示方式和用途脂倦,都需要給`UIDocumentInteractionController`指定文檔的URL番宁,所以我們通常使用下面的初始化方式,給`UIDocumentInteractionController`指定`文件的URL`赖阻。
  • (IBAction)presentPDFDocumentInteraction:(id)sender {
    UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:[[NSBundle mainBundle] URLForResource:@"Steve" withExtension:@"pdf"]];
    }

#展示第三方App列表
我們先實(shí)現(xiàn)`UIDocumentInteractionController`的第一個(gè)用途蝶押,展示可以操作PDF文件的第三方App列表。我們需要使用`UIDocumentInteractionController`提供的方法:
  • (BOOL)presentOpenInMenuFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated;

我在Button的觸發(fā)方法中添加下面的代碼,意思就是讓`UIDocumentInteractionController`的View在當(dāng)前控制器視圖上顯示:
[documentController presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES];
運(yùn)行程序火欧,點(diǎn)擊Button棋电,我們可以開始第一次展示測試?yán)病?
#第一次展示測試
一切準(zhǔn)備就緒之后,我開始進(jìn)行`UIDocumentInteractionController`的測試苇侵,點(diǎn)擊Button赶盔,就可以看到下面的界面啦。這說明我們的第一步成功了!!(真棒)

![可以操作PDF文件的第三方App列表](http://upload-images.jianshu.io/upload_images/1216322-f1a0a8924ea4b42d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

簡單介紹一下這個(gè)界面衅檀,這個(gè)視圖中的第一行列表顯示`AirDrop`招刨,是蘋果在`iOS 7`提供的一種跨設(shè)備分享的技術(shù),我會(huì)在后邊的文章中講解哀军。視圖中的第二行列表就是整個(gè)iOS系統(tǒng)中沉眶,可以操作PDF文檔的應(yīng)用程序列表,還包括了蘋果在`iOS 8`提供的`Share Extension`圖標(biāo)杉适,關(guān)于`Share Extension`谎倔,我會(huì)在后邊的文章中講解。視圖中的第三行列表猿推,就是現(xiàn)實(shí)設(shè)備可選的操作片习,如`Copy`,`Print`中,這里什么操作都沒有蹬叭,并不是說沒有可執(zhí)行的操作藕咏,而是我們沒有讓他顯示出來。

接著我試著點(diǎn)擊QQ圖標(biāo)秽五,打算把`史蒂夫?喬布斯傳`分享給我的好友孽查,然而意外發(fā)生了,`ZSDocumentInteractionTest`崩潰掉啦坦喘,而且還給出我們一段錯(cuò)誤提示:

2015-12-30 19:00:40.078 ZSDocumentInteractionTest[1254:344240] *** Assertion failure in -[_UIOpenWithAppActivity performActivity], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.29.5/UIDocumentInteractionController.m:408
2015-12-30 19:00:40.079 ZSDocumentInteractionTest[1254:344240] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UIDocumentInteractionController has gone away prematurely!'
*** First throw call stack:
(0x248e185b 0x35fa2dff 0x248e1731 0x25672ddb 0x290638c9 0x292695bb 0x28d5aefd 0x28d5e1a1 0x28b42107 0x28a50a55 0x28a50531 0x28a5042b 0x282e05cf 0x1acd03 0x1b17c9 0x248a4535 0x248a2a2f 0x247f50d9 0x247f4ecd 0x2db6aaf9 0x28a7e2dd 0x780ad 0x366f0873)
libc++abi.dylib: terminating with uncaught exception of type NSException

我看到錯(cuò)誤提示竟然指向了`UIDocumentInteractionController.m`文件盲再,而且錯(cuò)誤提示是`NSInternalInconsistencyException`(內(nèi)部不一致)和"UIDocumentInteractionController has gone away prematurely!"(UIDocumentInteractionController過早地被釋放掉啦)西设。由此我想出這個(gè)應(yīng)該是內(nèi)存過早釋放的一個(gè)錯(cuò)誤,然后我查閱了一下Apple Developer上的文檔答朋,原來贷揽,在ARC環(huán)境下展示`UIDocumentInteractionController`時(shí),當(dāng)我的函數(shù)方法調(diào)用完畢梦碗,退棧之后禽绪,`UIDocumentInteractionController`的實(shí)例就被釋放掉了,展示出來的這個(gè)View由`Quick Look`框架來操作洪规,并不會(huì)對(duì)`UIDocumentInteractionController`產(chǎn)生引用丐一。當(dāng)點(diǎn)擊View上面的Button時(shí),內(nèi)部操作仍然會(huì)繼續(xù)訪問這個(gè)`UIDocumentInteractionController`實(shí)例淹冰,就會(huì)報(bào)出上述錯(cuò)誤库车。

錯(cuò)誤原因找到了,那么解決原理也就清楚了樱拴,只要不讓`UIDocumentInteractionController`實(shí)例過早釋放就可以啦柠衍。我們可以將`UIDocumentInteractionController`聲明為一個(gè)`strong`類型的實(shí)例屬性,然后修改一下Button觸發(fā)方法就可以啦晶乔。(仍然不理解的朋友可以去GitHub上下載Demo測試)

@interface ViewController ()
@property (nonatomic, strong) UIDocumentInteractionController *documentController;
@end

我在Button的觸發(fā)方法中添加下面方法的調(diào)用,為了方便區(qū)分和理解珍坊,我把代碼封裝成了私有實(shí)例方法:
  • (void)presentOpenInMenu
    {
    // display third-party apps
    [self.documentController presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES];
    }

```Objective-c
- (IBAction)presentPGNDocumentInteraction:(id)sender {
    _documentController = [UIDocumentInteractionController interactionControllerWithURL:[[NSBundle mainBundle] URLForResource:@"Steve" withExtension:@"pdf"]];
    [self presentOpenInMenu];
}

修改完之后,運(yùn)行程序正罢,然后點(diǎn)擊Button阵漏,看到第一次測試時(shí)展示出來的圖片啦。然后再點(diǎn)QQ圖標(biāo)翻具,就可以正確地跳轉(zhuǎn)到QQ程序中履怯,選擇好友就可以分享史蒂夫?喬布斯傳啦。(QQ接收分享頁面就不展示了裆泳,想試驗(yàn)的可以手動(dòng)測試下)

展示可選操作

我們可以看到第一步圖示里面只有App圖標(biāo)叹洲,第二行操作列表中只有一個(gè)More。所以我們來展示UIDocumentInteractionController的第二種用途工禾,在第一步的基礎(chǔ)之上运提,顯示附加的操作選項(xiàng),闻葵。這需要我們使用UIDocumentInteractionController提供的另外一種展示方法:

- (BOOL)presentOptionsMenuFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated;

我們?cè)贐utton的觸發(fā)方法中添加下面方法的調(diào)用:

- (void)presentOptionsMenu
{
    // display third-party apps as well as actions, such as Copy, Print, Save Image, Quick Look
    [_documentController presentOptionsMenuFromRect:self.view.bounds inView:self.view animated:YES];
}

運(yùn)行程序民泵,點(diǎn)擊Button,我們可以看到下面的界面,多了CopyPrint的操作槽畔。Copy操作可以將文件拷貝到系統(tǒng)粘貼板中栈妆,而Print操作則是關(guān)聯(lián)打印機(jī)進(jìn)行打印操作的。(在這里我就不展示這倆種操作的具體界面啦!)

第三方App列表和附加操作界面

如果UIDocumentInteractionController關(guān)聯(lián)的是一個(gè)圖片文件签钩,這個(gè)界面還會(huì)提供一個(gè)Save Image的操作,用來直接保存圖片到系統(tǒng)的Photos中坏快,此外這個(gè)界面還提供了一個(gè)Quick Look操作铅檩,可以讓我們直接預(yù)覽喬布斯自傳PDF文檔,只不過需要我們?cè)俣鄬扅c(diǎn)代碼莽鸿,為了文章的合理性和結(jié)構(gòu)性昧旨,我決定在下面的標(biāo)題內(nèi)容中講解。(先賣個(gè)小關(guān)子O榈谩兔沃!)

直接預(yù)覽

UIDocumentInteractionController第三種預(yù)覽文檔內(nèi)容的用途非常重要,而且也是常見的级及。我會(huì)詳細(xì)地說一下如何通過UIDocumentInteractionController實(shí)現(xiàn)預(yù)覽史蒂夫?喬布斯傳乒疏。首先你需要為UIDocumentInteractionController指定一個(gè)delegate,并且實(shí)現(xiàn)下面的代理方法:

- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller;

這個(gè)代理方法主要是用來指定UIDocumentInteractionController要顯示的視圖所在的父視圖容器饮焦。這樣UIDocumentInteractionController才清楚在哪里展示Quick Look預(yù)覽內(nèi)容怕吴, 我在這里就指定Button所在的UIViewController來做UIDocumentInteractionController的代理對(duì)象,并且實(shí)現(xiàn)上面的代理方法县踢。在Button的觸發(fā)方法中添加下面的代碼

_documentController.delegate = self;

然后實(shí)現(xiàn)代理方法:

- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller
{
    return self;
}

UIDocumentInteractionController是繼承自NSObject的转绷,因而為了能夠?qū)崿F(xiàn)直接預(yù)覽,我們需要用到UIDocumentInteractionController提供的展示預(yù)覽的方法硼啤,

- (BOOL)presentPreviewAnimated:(BOOL)animated;

這個(gè)方法是以模態(tài)窗口通過Quick Look框架全屏顯示PDF的內(nèi)容议经,所以我們?cè)贐utton的觸發(fā)方法中添加下面方法的調(diào)用:

- (void)presentPreview
{
    // display PDF contents by Quick Look framework
    [self.documentController presentPreviewAnimated:YES];
}

然后運(yùn)行程序,點(diǎn)擊Button谴返,彈出了一個(gè)新視圖煞肾,可以看到史蒂夫?喬布斯傳的內(nèi)容,如下圖

直接預(yù)覽喬布斯自傳

展示預(yù)覽操作

通過上面的操作我們就可以欣賞閱讀我們想看的史蒂夫?喬布斯傳啦嗓袱,不過別忘記我們上面還賣了一個(gè)小關(guān)子扯旷,就是在展示可選操的時(shí)候,除了Copy索抓,Print钧忽,其實(shí)我們還可以展示Quick Look這個(gè)預(yù)覽操作。為什么我要賣關(guān)子呢逼肯,因?yàn)槲沂且粋€(gè)相信因果循環(huán)的人耸黑,我組織文章的邏輯是由淺入深,我設(shè)想通過一步步鋪墊來展開UIDocumentInteractionController所有特性篮幢。

好啦大刊,回歸正題!我們想要實(shí)現(xiàn)顯示Quick Look預(yù)覽操作三椿,其大部分的工作在直接預(yù)覽這一小節(jié)中都做完了缺菌,比如指定代理對(duì)象葫辐,然后實(shí)現(xiàn)這個(gè)代理方法來指定UIDocumentInteractionController的父視圖容器:

- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller;

由于我們已經(jīng)做完了所有準(zhǔn)備,在這一步伴郁,我們只需要將直接展示史蒂夫?喬布斯傳內(nèi)容的方法替換為下面這段耿战,展示可選操作列表的方法,就可以啦!

- (void)presentOptionsMenu
{
    // display third-party apps as well as actions, such as Copy, Print, Save Image, Quick Look
    [_documentController presentOptionsMenuFromRect:self.view.bounds inView:self.view animated:YES];
}

然后我們運(yùn)行程序焊傅,點(diǎn)擊Button剂陡,就可以看到Quick Look操作已經(jīng)顯示出來啦!如下圖:

展示Quick Look操作

如果我們點(diǎn)擊這個(gè)Quick Look操作狐胎,就可以看到直接預(yù)覽內(nèi)容時(shí)所展示的界面啦鸭栖。好啦,通過UIDocumentInteractionController實(shí)現(xiàn)史蒂夫?喬布斯傳的預(yù)覽和分享就到此結(jié)束啦握巢。我會(huì)在下面的章節(jié)中晕鹊,講解通過其他技術(shù)實(shí)現(xiàn)喬布斯自傳的分享和操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末暴浦,一起剝皮案震驚了整個(gè)濱河市捏题,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌肉渴,老刑警劉巖公荧,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異同规,居然都是意外死亡循狰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門券勺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绪钥,“玉大人,你說我怎么就攤上這事关炼〕谈梗” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵儒拂,是天一觀的道長寸潦。 經(jīng)常有香客問我,道長社痛,這世上最難降的妖魔是什么见转? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蒜哀,結(jié)果婚禮上斩箫,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好乘客,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布狐血。 她就那樣靜靜地躺著,像睡著了一般易核。 火紅的嫁衣襯著肌膚如雪匈织。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天耸成,我揣著相機(jī)與錄音,去河邊找鬼浴鸿。 笑死井氢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的岳链。 我是一名探鬼主播花竞,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼掸哑!你這毒婦竟也來了约急?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤苗分,失蹤者是張志新(化名)和其女友劉穎厌蔽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摔癣,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奴饮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了择浊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戴卜。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖琢岩,靈堂內(nèi)的尸體忽然破棺而出投剥,到底是詐尸還是另有隱情,我是刑警寧澤担孔,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布江锨,位于F島的核電站,受9級(jí)特大地震影響糕篇,放射性物質(zhì)發(fā)生泄漏泳桦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一娩缰、第九天 我趴在偏房一處隱蔽的房頂上張望灸撰。 院中可真熱鬧,春花似錦、人聲如沸浮毯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽债蓝。三九已至壳鹤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饰迹,已是汗流浹背芳誓。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啊鸭,地道東北人锹淌。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像赠制,于是被迫代替她去往敵國和親赂摆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容