iOS 保存圖片到【自定義相冊】

一、保存圖片到自定義相冊的三個步驟

  • 1.保存圖片到相冊【相機膠卷】
    1>、C語言保存
    2>、#import <AssetsLibrary/AssetsLibrary.h> 保存

    AssetsLibrary框架: iOS9 之后開始被廢棄

    3>、#import <Photos/Photos.h> 保存

    Photos框架 iOS 8 開始就可以用了

  • 2.擁有一個自定義相冊:使用AssetsLibraryPhotos框架

  • 3.將剛才保存到【相機膠卷中的圖片】引用到【自定義的相冊】:使用AssetsLibraryPhotos框架

二、單純的C語言保存圖片到相冊(不使用AssetsLibraryPhotos框架)

  • 2.1、保存圖片到相冊

    /**
     <#Description#>
    
      第1個參數:UIIMage 對象
      第2個參數:監聽對象
      第3個參數:保存后所走【監聽對象】的方法
      第4個參數:描述文字,一般為 niul
    */
    UIImageWriteToSavedPhotosAlbum(self.photoimageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
    
    #pragma mark 保存成功后所走的方法
    - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
    
         // 保存完畢
         if (error) {
      
            NSLog(@"保存失敗");
         }else{
      
            NSLog(@"保存成功");
         }
    }
    

    提示:上面第三個參數是要按照蘋果的格式來寫方法名的,點擊方法進去 我們可以到如下代碼:
    // Adds a photo to the saved photos album. The optional completionSelector should have the form:
    // - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;
    蘋果讓我們按照他們的格式來寫方法,我們可以把他們的方法名替換為任意的名字,如:

    - (void)a:(UIImage *)image b:(NSError *)error c:(void *)contextInfo;
    

三、Photos 框架

  • 3.1、Photos 框架基本認識,我們可以在 Help->Developer Documentation-> 選擇OC或者Swift 搜索 Photos

    Photos 框架檢索

    Photos 是用來處理 視頻 與 圖片 的,下面是其主要的類

    • <1>、PHAsset:一個 PHAsset 對象就代表相冊中的一張圖片或者一個視頻

      (1)、查:[PHAsset fetch.....]
      (2)、增刪改:PHAssetChangeRequest,改變圖片 (包括 圖片/視頻 相關的所有改動操作)

    • <2>、:PHAssetCollection: 一個PHAssetCollection就代表一個相冊
      (1)、查:[PHAssetCollection fetch.....]
      (2)、增刪改:PHAssetCollectionChangeRequest,改變相冊 (包括 相冊 相關的所有改動操作)

    提示:所有的增刪改的操作都要放到:-[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'方法里面

  • 3.2、使用 Photos 框架保存圖片到【相機膠卷】

    • 異步操作保存到相冊

      [[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
      
           [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image];
      
      } completionHandler:^(BOOL success, NSError * _Nullable error) {
      
           if (error) {
                [SVProgressHUD showErrorWithStatus:@"保存失敗"];
           }else{
                [SVProgressHUD showErrorWithStatus:@"保存成功"];
          }
      }];
      
    • 同步操作保存到相冊

      NSError *error = nil;
      
      [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
      
         [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image];
      
      } error:&error];
      
      if (error) {
          [SVProgressHUD showErrorWithStatus:@"保存失敗"];
      }else{
          [SVProgressHUD showErrorWithStatus:@"保存成功"];
      }
      

    提示:使用 Photos 框架保存圖片到【相機膠卷】必須把代碼放到上面的兩個方法里面,否則會報下面的錯
    reason: 'This method can only be called from inside of -[PHPhotoLibrary performChanges:completionHandler:] or -[PHPhotoLibrary performChangesAndWait:error:]'

  • 3.3、創建新的相冊(自定義一個屬于自己app的相冊),提示:創建相冊之前要先判斷相冊是否存在,存在就不再創建

    NSError *error = nil;
    
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
      
         // 獲取app的名字
         NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
         // 創建一個自定義的相冊 
         [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle: appName];
      
     } error:&error];
    
     if (error) {
            [SVProgressHUD showErrorWithStatus:@"創建相冊失敗"];
     }else{
            [SVProgressHUD showErrorWithStatus:@"創建相冊成功"];
     }
    

    提示一kCFBundleNameKey = @"CFBundleName",下面的兩句是一個意思

    • NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
      下面是:C 的strting轉為NSString
    • NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleNameKey];

    提示二:Foundation 和 Core Foundation 的數據類型可以相互轉換,比如:NSString * 和 CFStringRef,如下面的例子:

    NSString *string = (NSString *)kCFBundleNameKey;
    CFStringRef string = (CFStringRef)@"name";
    
  • 3.4、查詢相冊 (自定義相冊或者系統相冊)

    /**
      PHAssetCollectionTypeAlbum      = 1, 自定義相冊(普通的相冊)
      PHAssetCollectionTypeSmartAlbum = 2, 智能相冊(系統自帶的相冊),如:Camera Roll
      PHAssetCollectionTypeMoment     = 3, 按照時刻分的相冊
     */
    
    // 相機膠卷相冊,打印:Camera Roll
    // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
    // 自定義相冊,打印:自定義相冊的名字
    PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    for (PHAssetCollection *collection in collections) {
      
      NSLog(@"相冊的名字=%@",collection.localizedTitle);
    }
    
  • 3.5.創建相冊與查詢相冊合在一起,如下

    // 獲取app的名字
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
    
    /**
      PHAssetCollectionTypeAlbum      = 1, 自定義相冊(普通的相冊)
      PHAssetCollectionTypeSmartAlbum = 2, 智能相冊(系統自帶的相冊),如:Camera Roll
      PHAssetCollectionTypeMoment     = 3, 按照時刻分的相冊
     */
    
     // 相機膠卷相冊,打印:Camera Roll
     // PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil];
     // 自定義相冊,打印:自定義相冊的名字
     PHFetchResult<PHAssetCollection *> *collections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    
     // 自己的相冊
     PHAssetCollection *appCollection = nil;
    
     for (PHAssetCollection *collection in collections) {
      
        NSLog(@"相冊的名字=%@",collection.localizedTitle);
      
        if ([collection.localizedTitle isEqualToString:appName]) {
          
             appCollection = collection;
             break;
        }
     }
    
     if (appCollection == nil) {
      
         NSError *error = nil;
      
         __block NSString *createCollectionID = nil;
      
         [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
          
             // 獲取app的名字
             NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
             // 獲取相冊的唯一標識符
             createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier;
          
          } error:&error];
      
          if (error) {
              [SVProgressHUD showErrorWithStatus:@"創建相冊失敗"];
          }else{
          
              appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject;
              [SVProgressHUD showErrorWithStatus:@"創建相冊成功"];
          }
      }
    
      // 相冊一定存在
      NSLog(@"相冊已經存在");
    

    提示:這里有一個技術點就是:根據創建相冊返回的相冊唯一標識符獲取相冊對象,如下代碼:

    // 自己的相冊
    PHAssetCollection *appCollection = nil;
    if (appCollection == nil) {
    
        NSError *error = nil;
    
        __block NSString *createCollectionID = nil;
    
        [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
    
            // 獲取app的名字
            NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
            // 獲取相冊的唯一標識符
            createCollectionID = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:appName].placeholderForCreatedAssetCollection.localIdentifier;
    
         } error:&error];
    
         if (error) {
            [SVProgressHUD showErrorWithStatus:@"創建相冊失敗"];
         }else{
            appCollection = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[createCollectionID] options:nil].firstObject;
            [SVProgressHUD showErrorWithStatus:@"創建相冊成功"];
         }
     }
    
    • 再次提示:只有上面的block代碼執行完才代表相冊可能存在,所以,獲取PHAssetCollection放在了下面
  • 3.6、保存圖片到自定義的相冊

    -(void)savePhotosToAppPhotoCollection{
    
       // 同步操作保存到【相機膠卷】
       __block PHObjectPlaceholder *placeholderForCreatedAsset;
       NSError *error = nil;
       [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
      
            placeholderForCreatedAsset = [PHAssetChangeRequest creationRequestForAssetFromImage:self.photoimageView.image].placeholderForCreatedAsset;
      
         } error:&error];
    
         if (error) {
             [SVProgressHUD showErrorWithStatus:@"保存圖片失敗"];
             return;
         }
    
         // 獲得自定義相冊
         PHAssetCollection *createCollection = [JKPhotosKit createPHAssetCollection];
         if (createCollection == nil) {
              [SVProgressHUD showErrorWithStatus:@"創建相冊失敗"];
              return;
         }
    
         // 添加剛才保存的圖片到 【自定義相冊】
         [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
              // 獲取自定義對象的操作對象
              PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createCollection];
              // 把圖片插入到自定義相冊的第一個位置
              [request insertAssets:@[placeholderForCreatedAsset] atIndexes:[NSIndexSet indexSetWithIndex:0]];
      
          } error:&error];
    
          if (error) {
              [SVProgressHUD showErrorWithStatus:@"保存圖片失敗"];
          }else{
              [SVProgressHUD showSuccessWithStatus:@"保存圖片成功"];
          }
    }
    
  • 3.7、用戶相冊權限的判斷

    // 請求或者訪問用戶訪問權限:
    // 如果還沒有做出選擇,會自動彈框,用戶對彈框做出選擇后才會調用block;
    // 如果用戶之前已經做出過選擇,會自動執行block
    /**
      PHAuthorizationStatusNotDetermined = 0,還沒決定
      PHAuthorizationStatusRestricted = 1,沒有授權,不能訪問用戶相冊
      PHAuthorizationStatusDenied = 2,用戶拒絕這個應用
      PHAuthorizationStatusAuthorized = 3 用戶授權這個app訪問這個相冊
     */
    // 獲取用戶之前的狀態
    PHAuthorizationStatus oldStatus = [PHPhotoLibrary authorizationStatus];
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    
      // 用戶決絕當前 App 訪問相冊
      dispatch_async(dispatch_get_main_queue(), ^{
          
          if (status == PHAuthorizationStatusDenied) {
             
              if (oldStatus != PHAuthorizationStatusDenied) {
                  
                  // 提醒用戶打開開關
                  
              }else{
                  
              }
              
          }else if (status == PHAuthorizationStatusAuthorized){
              // 用戶允許當前 App 訪問相冊
              [self trueSaveImageToAppPhotoCollection:saveImage];
              
          }else if (status == PHAuthorizationStatusRestricted){
              // 因系統原因無法訪問相冊
              [SVProgressHUD showErrorWithStatus:@"因系統原因無法訪問相冊"];
          }
      });
    }];
    

    提示:上面所有的完整代碼都在 JKPhotosKit類里面,需要的請下載 demo

    • JKPhotosKit 類的使用方法:保存圖片到自定的相冊
      [JKPhotosKit savePhotosToAppPhotoCollection:UIImage對象];
      效果圖

完整代碼都在 JKPhotosKit類里面,需要的請下載 demo

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容