通过UIDocumentInteractionController预览和分享史蒂夫•乔布斯传
前言
朋友分享推薦給我一本PDF格式的史蒂夫?喬布斯傳,閱讀了幾篇,很受感觸,于是想把他分享給大家欣賞閱讀。早起閑來無事,正好就接著寫篇文章來分享一下!我在“iOS實現App之間的內容分享”這篇文章中詳細講解了通過注冊UTI的方式讓我們的App支持分享,也簡單地說了一下App內部怎么處理分享。同時,我也指出了在iOS系統跨App分享內容的幾種常用技術,比如URL Scheme,AirDrop, UIDocumentInteractionController,UIActivityViewController這幾種。這一篇文章,我們來談一下最基礎的原始方法,怎么通過使用UIDocumentInteractionController來預覽、操作和分享史蒂夫?喬布斯傳。
簡介
從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 的開發中使用的。遍觀UIDocumentInteractionController的屬性和方法可以看出,UIDocumentInteractionController主要給我們提供了三種用途,我會在下面的內容中逐條的講解UIDocumentInteraction的每一種用途的具體使用:
準備階段
首先我創建了一個新的應用方便演示和截圖,我把它命名為ZSDocumentInteractionTest,然后拖入PDF格式的史蒂夫?喬布斯傳到ZSDocumentInteractionTest項目的bundle中。然后在Storyboard的ViewController中添加了一個Button作為UIDocumentInteractionController的觸發操作(這些操作都比較簡單,就不在這里用圖展示啦)。運行程序,我們就可以看到Button啦,截圖如下。然后我們就可以在Button的觸發方法中,操作UIDocumentInteractionController來顯示或者分享我們的史蒂夫?喬布斯傳啦,具體的應用詳情可以參考GitHub上的Demo:ZSDocumentInteractionTest。
在ViewController的視圖 中顯示Button
初始化
不管我們使用哪種UIDocumentInteractionController的展示方式和用途,都需要給UIDocumentInteractionController指定文檔的URL,所以我們通常使用下面的初始化方式,給UIDocumentInteractionController指定文件的URL。
- (IBAction)presentPDFDocumentInteraction:(id)sender {UIDocumentInteractionController *documentController = [UIDocumentInteractionController interactionControllerWithURL:[[NSBundle mainBundle] URLForResource:@"Steve" withExtension:@"pdf"]]; }展示第三方App列表
我們先實現UIDocumentInteractionController的第一個用途,展示可以操作PDF文件的第三方App列表。我們需要使用UIDocumentInteractionController提供的方法:
- (BOOL)presentOpenInMenuFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated;我在Button的觸發方法中添加下面的代碼,意思就是讓UIDocumentInteractionController的View在當前控制器視圖上顯示:
[documentController presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES];運行程序,點擊Button,我們可以開始第一次展示測試啦。
第一次展示測試
一切準備就緒之后,我開始進行UIDocumentInteractionController的測試,點擊Button,就可以看到下面的界面啦。這說明我們的第一步成功了!!(真棒)
可以操作PDF文件的第三方App列表
簡單介紹一下這個界面,這個視圖中的第一行列表顯示AirDrop,是蘋果在iOS 7提供的一種跨設備分享的技術,我會在后邊的文章中講解。視圖中的第二行列表就是整個iOS系統中,可以操作PDF文檔的應用程序列表,還包括了蘋果在iOS 8提供的Share Extension圖標,關于Share Extension,我會在后邊的文章中講解。視圖中的第三行列表,就是現實設備可選的操作,如Copy,Print中,這里什么操作都沒有,并不是說沒有可執行的操作,而是我們沒有讓他顯示出來。
接著我試著點擊QQ圖標,打算把史蒂夫?喬布斯傳分享給我的好友,然而意外發生了,ZSDocumentInteractionTest崩潰掉啦,而且還給出我們一段錯誤提示:
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我看到錯誤提示竟然指向了UIDocumentInteractionController.m文件,而且錯誤提示是NSInternalInconsistencyException(內部不一致)和"UIDocumentInteractionController has gone away prematurely!"(UIDocumentInteractionController過早地被釋放掉啦)。由此我想出這個應該是內存過早釋放的一個錯誤,然后我查閱了一下Apple Developer上的文檔,原來,在ARC環境下展示UIDocumentInteractionController時,當我的函數方法調用完畢,退棧之后,UIDocumentInteractionController的實例就被釋放掉了,展示出來的這個View由Quick Look框架來操作,并不會對UIDocumentInteractionController產生引用。當點擊View上面的Button時,內部操作仍然會繼續訪問這個UIDocumentInteractionController實例,就會報出上述錯誤。
錯誤原因找到了,那么解決原理也就清楚了,只要不讓UIDocumentInteractionController實例過早釋放就可以啦。我們可以將UIDocumentInteractionController聲明為一個strong類型的實例屬性,然后修改一下Button觸發方法就可以啦。(仍然不理解的朋友可以去GitHub上下載Demo測試)
@interface ViewController () @property (nonatomic, strong) UIDocumentInteractionController *documentController; @end我在Button的觸發方法中添加下面方法的調用,為了方便區分和理解,我把代碼封裝成了私有實例方法:
- (void)presentOpenInMenu {// display third-party apps[self.documentController presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES]; } - (IBAction)presentPGNDocumentInteraction:(id)sender {_documentController = [UIDocumentInteractionController interactionControllerWithURL:[[NSBundle mainBundle] URLForResource:@"Steve" withExtension:@"pdf"]];[self presentOpenInMenu]; }修改完之后,運行程序,然后點擊Button,看到第一次測試時展示出來的圖片啦。然后再點QQ圖標,就可以正確地跳轉到QQ程序中,選擇好友就可以分享史蒂夫?喬布斯傳啦。(QQ接收分享頁面就不展示了,想試驗的可以手動測試下)
展示可選操作
我們可以看到第一步圖示里面只有App圖標,第二行操作列表中只有一個More。所以我們來展示UIDocumentInteractionController的第二種用途,在第一步的基礎之上,顯示附加的操作選項,。這需要我們使用UIDocumentInteractionController提供的另外一種展示方法:
- (BOOL)presentOptionsMenuFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated;我們在Button的觸發方法中添加下面方法的調用:
- (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]; }運行程序,點擊Button,我們可以看到下面的界面,多了Copy和Print的操作。Copy操作可以將文件拷貝到系統粘貼板中,而Print操作則是關聯打印機進行打印操作的。(在這里我就不展示這倆種操作的具體界面啦!)
第三方App列表和附加操作界面
如果UIDocumentInteractionController關聯的是一個圖片文件,這個界面還會提供一個Save Image的操作,用來直接保存圖片到系統的Photos中,此外這個界面還提供了一個Quick Look操作,可以讓我們直接預覽喬布斯自傳PDF文檔,只不過需要我們再多寫點代碼,為了文章的合理性和結構性,我決定在下面的標題內容中講解。(先賣個小關子!!)
直接預覽
UIDocumentInteractionController第三種預覽文檔內容的用途非常重要,而且也是常見的。我會詳細地說一下如何通過UIDocumentInteractionController實現預覽史蒂夫?喬布斯傳。首先你需要為UIDocumentInteractionController指定一個delegate,并且實現下面的代理方法:
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller;這個代理方法主要是用來指定UIDocumentInteractionController要顯示的視圖所在的父視圖容器。這樣UIDocumentInteractionController才清楚在哪里展示Quick Look預覽內容, 我在這里就指定Button所在的UIViewController來做UIDocumentInteractionController的代理對象,并且實現上面的代理方法。在Button的觸發方法中添加下面的代碼
_documentController.delegate = self;然后實現代理方法:
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller {return self; }UIDocumentInteractionController是繼承自NSObject的,因而為了能夠實現直接預覽,我們需要用到UIDocumentInteractionController提供的展示預覽的方法,
- (BOOL)presentPreviewAnimated:(BOOL)animated;這個方法是以模態窗口通過Quick Look框架全屏顯示PDF的內容,所以我們在Button的觸發方法中添加下面方法的調用:
- (void)presentPreview {// display PDF contents by Quick Look framework[self.documentController presentPreviewAnimated:YES]; }然后運行程序,點擊Button,彈出了一個新視圖,可以看到史蒂夫?喬布斯傳的內容,如下圖
直接預覽喬布斯自傳
展示預覽操作
通過上面的操作我們就可以欣賞閱讀我們想看的史蒂夫?喬布斯傳啦,不過別忘記我們上面還賣了一個小關子,就是在展示可選操的時候,除了Copy,Print,其實我們還可以展示Quick Look這個預覽操作。為什么我要賣關子呢,因為我是一個相信因果循環的人,我組織文章的邏輯是由淺入深,我設想通過一步步鋪墊來展開UIDocumentInteractionController所有特性。
好啦,回歸正題!我們想要實現顯示Quick Look預覽操作,其大部分的工作在直接預覽這一小節中都做完了,比如指定代理對象,然后實現這個代理方法來指定UIDocumentInteractionController的父視圖容器:
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller;由于我們已經做完了所有準備,在這一步,我們只需要將直接展示史蒂夫?喬布斯傳內容的方法替換為下面這段,展示可選操作列表的方法,就可以啦!
- (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]; }然后我們運行程序,點擊Button,就可以看到Quick Look操作已經顯示出來啦!如下圖:
展示Quick Look操作
如果我們點擊這個Quick Look操作,就可以看到直接預覽內容時所展示的界面啦。好啦,通過UIDocumentInteractionController實現史蒂夫?喬布斯傳的預覽和分享就到此結束啦。我會在下面的章節中,講解通過其他技術實現喬布斯自傳的分享和操作。
總結
以上是生活随笔為你收集整理的通过UIDocumentInteractionController预览和分享史蒂夫•乔布斯传的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实例19:python
- 下一篇: win7 mysql msi_windo