將圖片保存到系統相冊中, PHPhotoLibrary的簡單使用

一. 最簡單的保存函數

  1. UIImage的函數來保存圖片
    • 較為簡單, 只需要一個函數一個方法就可以保存

    • 但是不能創建相冊, 保存的圖片會直接保存到默認的系統相冊中

        /** 該函數用于將圖片保存到系統相冊中
          UIImage * _Nonnull image : 要保存的圖片
          id  _Nullable completionTarget : 調用completionSelector方法的對象, 一般為self
          SEL  _Nullable completionSelector : 當保存完成調用的方法, 是一個系統指定的方法
          void * _Nullable contextInfo : 上下文信息, 用于傳給完成后的回調方法, 一般為nil
        */
        UIImageWriteToSavedPhotosAlbum(_image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
        
        - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
            
            if (error) {
                NSLog(@"保存失敗");
            } else {
                NSLog(@"保存成功");
            }
        }
      
    • 注意點

      1. 第三個參數一定要使用系統的回調方法, 否則這個方法會報錯
      2. 系統指定的image: didFinishSavingWithError: contextInfo:方法一定要實現, 否則也會出現問題

二. 使用PHPhotoLibrary來保存圖片

  1. 框架的簡單介紹:

    1. PHPhotoLibrary類, 專門用于管理系統的相片, 相簿等功能, 他可以獲取系統相冊中的相片信息, 也可以將App中獲取的圖片/相片存到手機相冊中, 以及iCloud Photos中.
    2. 對于手機相冊的各種操作, 幾乎都是通過PHPhotoLibrary的單例對象, 在ChangeBlock中, 以ChangeRequest來執行的
      • 相片請求操作: PHAssetChangeRequest
      • 相冊請求操作: PHAssetCollectionChangeRequest
      • 相冊列表請求操作: PHCollectionListChangeRequest(小的暫時沒試過)
    3. PHObjectPlaceholder對象
      • 這個對象是用于存儲圖片時的占位對象
      • 如果你想保存一個圖片到一個相冊中, 需要先將這個占位對象添加到相冊中, 當ChangeBlock調用結束之后, 會根據占位對象的標識符搜索到占位對象的所在位置, 然后在保存圖片
    4. PHAuthorization: 用于查看當前App的相冊授權狀態
      • 這個類用于獲取當前你的App, 系統對其相冊訪問權限的授權狀態
      • 通過對四種不同的授權狀態的判斷, 我們可以做出對應的操作
        • PHAuthorizationStatusNotDetermined : 用戶還沒有決定是否授權
        • PHAuthorizationStatusRestricted : 訪問權限受限制, 這個很少見, 如家長模式的限制才會有
        • PHAuthorizationStatusDenied : 用戶拒絕App訪問相冊
        • PHAuthorizationStatusAuthorized : 用戶已經授權了訪問
    5. PHFetchResult: 檢索相簿中的相冊/相片
      • 這個類創建的對象, 是一個有序集合, 可以用于保存系統相簿中的相片/相冊的搜索結果列表
      • 該對象的每個元素, 都有一個localizedTitle, 即搜索得到的相片/相冊的名稱, 可以通過這個屬性來獲得指定的相冊/相片
      • 一般是通過遍歷的方式, 然后判斷localizedTitle, 取得我們想要的相片/相冊
  2. 保存圖片的步驟

    1. 提供給外界調用的方法, 通過傳入要保存的圖片, 和指定的相冊名稱來保存一張圖片
      • 在這個方法中, 要獲取當前App的相冊授權狀態

      • 如果用戶授權了, 就直接調用步驟2的方法, 保存圖片

      • 如果用戶沒有確定是否授權, 要創建授權申請, 讓用戶選擇

      • 如果用戶已經拒絕了授權, 要顯示一個指示框, 讓用戶去打開授權

          + (void)saveImage:(UIImage *)image assetCollectionName:(NSString *)collectionName {
              
              // 1. 獲取當前App的相冊授權狀態
              PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus];
              
              // 2. 判斷授權狀態
              if (authorizationStatus == PHAuthorizationStatusAuthorized) {
                  
                  // 2.1 如果已經授權, 保存圖片(調用步驟2的方法)
                  [self saveImage:image toCollectionWithName:collectionName];
                  
              } else if (authorizationStatus == PHAuthorizationStatusNotDetermined) { // 如果沒決定, 彈出指示框, 讓用戶選擇
                  
                  [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
                      
                      // 如果用戶選擇授權, 則保存圖片
                      if (status == PHAuthorizationStatusAuthorized) {
                          [self saveImage:image toCollectionWithName:collectionName];
                      }
                  }];
                  
              } else {
                  
                  [SVProgressHUD showWithStatus:@"請在設置界面, 授權訪問相冊"];
              }
          }
        
    2. 用于保存圖片的方法, 通過外接接口獲取到的圖片, 相冊名稱來進行保存
      • 將一個相片保存到一個自定義的相冊, 需要同時創建相片變動請求相冊變動請求

      • 根據傳入的相冊名, 要判斷一下當前系統是否有這個相冊(這里需要步驟3的方法, 傳入相冊名稱, 來獲取相冊)

      • 在這個步驟, 需要用到的四個核心對象為PHPhotoLibrary, PHAssetCollectionChangeRequest, PHAssetChangeRequest, 以及PHObjectPlaceholder

          // 保存圖片
          + (void)saveImage:(UIImage *)image toCollectionWithName:(NSString *)collectionName {
              
              // 1. 獲取相片庫對象
              PHPhotoLibrary *library = [PHPhotoLibrary sharedPhotoLibrary];
              
              // 2. 調用changeBlock
              [library performChanges:^{
                  
                  // 2.1 創建一個相冊變動請求
                  PHAssetCollectionChangeRequest *collectionRequest;
                  
                  // 2.2 取出指定名稱的相冊
                  PHAssetCollection *assetCollection = [self getCurrentPhotoCollectionWithTitle:collectionName];
                  
                  // 2.3 判斷相冊是否存在
                  if (assetCollection) { // 如果存在就使用當前的相冊創建相冊請求
                      collectionRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:assetCollection];
                  } else { // 如果不存在, 就創建一個新的相冊請求
                      collectionRequest = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:collectionName];
                  }
                  
                  // 2.4 根據傳入的相片, 創建相片變動請求
                  PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
                  
                  // 2.4 創建一個占位對象
                  PHObjectPlaceholder *placeholder = [assetRequest placeholderForCreatedAsset];
                  
                  // 2.5 將占位對象添加到相冊請求中
                  [collectionRequest addAssets:@[placeholder]];
                  
              } completionHandler:^(BOOL success, NSError * _Nullable error) {
                  
                  // 3. 判斷是否出錯, 如果報錯, 聲明保存不成功
                  if (error) {
                      [SVProgressHUD showErrorWithStatus:@"保存失敗"];
                  } else {
                      [SVProgressHUD showSuccessWithStatus:@"保存成功"];
                  }
              }];
          }
        
    3. 步驟三用于獲取當前系統中是否有指定的相冊
      • 如果有的話, 就返回已有相冊

      • 如果沒有的話, 就返回nil, 讓步驟二去創建一個新的系統相冊

      • 此處需要用到的關鍵類為: FHFetchResult, 用于搜索相冊/相片名稱的集合對象

      • 通過搜索結果的localizedTitle來找到對應的相冊

          + (PHAssetCollection *)getCurrentPhotoCollectionWithTitle:(NSString *)collectionName {
              
              // 1. 創建搜索集合
              PHFetchResult *result = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
              
              // 2. 遍歷搜索集合并取出對應的相冊
              for (PHAssetCollection *assetCollection in result) {
                  
                  if ([assetCollection.localizedTitle containsString:collectionName]) {
                      return assetCollection;
                  }
              }
              
              return nil;
          }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容