#import "ViewController.h" #import <Photos/Photos.h> @interface ViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (IBAction)selectImage { [self getThumbnailImages]; } /** * 獲得所有相簿的原圖 */ - (void)getOriginalImages { // 獲得所有的自定義相簿 PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; // 遍歷所有的自定義相簿 for (PHAssetCollection *assetCollection in assetCollections) { [self enumerateAssetsInAssetCollection:assetCollection original:YES]; } // 獲得相機膠卷 PHAssetCollection *cameraRoll = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil].lastObject; [self enumerateAssetsInAssetCollection:cameraRoll original:YES]; } /** * 獲得所有相簿中的縮略圖 */ - (void)getThumbnailImages { // 獲得所有的自定義相簿 PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; // 遍歷所有的自定義相簿 for (PHAssetCollection *assetCollection in assetCollections) { [self enumerateAssetsInAssetCollection:assetCollection original:NO]; } // 獲得相機膠卷 PHAssetCollection *cameraRoll = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil].lastObject; [self enumerateAssetsInAssetCollection:cameraRoll original:NO]; } /** * 遍歷相簿中的所有圖片 * * @param assetCollection 相簿 * @param original 是否要原圖 */ - (void)enumerateAssetsInAssetCollection:(PHAssetCollection *)assetCollection original:(BOOL)original { NSLog(@"相簿名:%@", assetCollection.localizedTitle); PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; // 同步獲得圖片, 只會返回1張圖片 options.synchronous = YES; // 獲得某個相簿中的所有PHAsset對象 PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil]; for (PHAsset *asset in assets) { // 是否要原圖 CGSize size = original ? CGSizeMake(asset.pixelWidth, asset.pixelHeight) : CGSizeZero; // 從asset中獲得圖片 [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { NSLog(@"%@", result); }]; } } /** * 獲得相機膠卷中的所有圖片 */ - (void)getImagesFromCameraRoll { // 獲得相機膠卷中的所有圖片 PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsWithOptions:nil]; __block int count = 0; for (PHAsset *asset in assets) { [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:CGSizeMake(asset.pixelWidth, asset.pixelHeight) contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { NSLog(@"%@ - %zd", result, count++); }]; } } /** * 利用UIImagePickerController挑選圖片 */ - (void)getImageFromIpc { // UIImagePickerController : 可以從系統自帶的App(照片\相機)中獲得圖片 // 判斷相冊是否可以打開 if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) return; UIImagePickerController *ipc = [[UIImagePickerController alloc] init]; // 打開照片應用(顯示所有相簿) ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; // 打開照片應用(只顯示"時刻"這個相簿) // ipc.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; // 照相機 // ipc.sourceType = UIImagePickerControllerSourceTypeCamera; ipc.delegate = self; [self presentViewController:ipc animated:YES completion:nil]; } #pragma mark - <UIImagePickerControllerDelegate> - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { // 銷毀控制器 [picker dismissViewControllerAnimated:YES completion:nil]; // 設置圖片 self.imageView.image = info[UIImagePickerControllerOriginalImage]; } @end
總結:1:從相冊中選取照片可以利用UIImagePickerController,前提是必須遵守兩個協議:
<UIImagePickerControllerDelegate, UINavigationControllerDelegate>但是此種方法只能獲取到相冊中的一張照片。使用方法如下:1:可以先判斷其是否支持相機或是相冊,不支持直接return,不執行以下代碼 2:創建對象,設置代理,在設置sourceType(注意兩種類型的區別),彈出就用presentViewController可以彈出相冊,dissmiss返回到應用。實現代理方法獲取圖片: self.imageView.image = info[UIImagePickerControllerOriginalImage];3:UIImagePickerController顯示中文界面:
1.Project-->Info-->Localizations添加Chinese
2.修改Target-->Info-->Localization native development region : China
- (void)getImageFromIpc
{
// UIImagePickerController : 可以從系統自帶的App(照片\相機)中獲得圖片
// 判斷相冊是否可以打開
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) return;
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
// 打開照片應用(顯示所有相簿)
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// 打開照片應用(只顯示"時刻"這個相簿)
// ipc.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// 照相機
// ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
[self presentViewController:ipc animated:YES completion:nil];
}
#pragma mark - <UIImagePickerControllerDelegate>
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
// 銷毀控制器
[picker dismissViewControllerAnimated:YES completion:nil];
// 設置圖片
self.imageView.image = info[UIImagePickerControllerOriginalImage];
}
2:若是想多選照片:1:可用系統框架:#import <Photos/Photos.h> 2:使用步驟:1:先獲得所有相簿,在獲得相簿膠卷
PHAssetCollection
2:遍歷相簿數組,得到每一個相冊照片PHAsset,再利用PHAsset請求獲得每一張照片
3:若想做成系統相簿的樣式:1:此界面可采用九宮格搭建,或是采用collection搭建,建議用后者,因為后者可以有循環利用的機制,節省
內存
2:如下界面搭建:可以監聽每張圖片的點擊,當點擊到某張圖片的時候,將封裝好的蒙板和對勾,蓋在上面,或是再移除
3:
## 獲得自定義的所有相簿 ```objc // 獲得所有的自定義相簿 PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; // 遍歷所有的自定義相簿 for (PHAssetCollection *assetCollection in assetCollections) { } ``` ## 獲得相機膠卷相簿 ```objc // 獲得相機膠卷 PHAssetCollection *cameraRoll = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil].lastObject; ``` ## 獲得某個相簿的縮略圖 ```objc PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; // 同步獲得圖片, 只會返回1張圖片 options.synchronous = YES; // 獲得某個相簿中的所有PHAsset對象 PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil]; for (PHAsset *asset in assets) { CGSize size = CGSizeZero; // 從asset中獲得圖片 [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { NSLog(@"%@", result); }]; } ``` ## 獲得某個相簿的原圖 ```objc PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; // 同步獲得圖片, 只會返回1張圖片 options.synchronous = YES; // 獲得某個相簿中的所有PHAsset對象 PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil]; for (PHAsset *asset in assets) { CGSize size = CGSizeMake(asset.pixelWidth, asset.pixelHeight); // 從asset中獲得圖片 [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { NSLog(@"%@", result); }]; } ``` ## 利用UIImagePickerController挑選圖片 ```objc // UIImagePickerController : 可以從系統自帶的App(照片\相機)中獲得圖片 // 判斷相冊是否可以打開 if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) return; UIImagePickerController *ipc = [[UIImagePickerController alloc] init]; // 打開照片應用(顯示所有相簿) ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; // 打開照片應用(只顯示"時刻"這個相簿) // ipc.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; // 照相機 // ipc.sourceType = UIImagePickerControllerSourceTypeCamera; ipc.delegate = self; [self presentViewController:ipc animated:YES completion:nil]; #pragma mark - <UIImagePickerControllerDelegate> - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { // 銷毀控制器 [picker dismissViewControllerAnimated:YES completion:nil]; // 設置圖片 self.imageView.image = info[UIImagePickerControllerOriginalImage]; } ``` ## NaN錯誤 - 錯誤起因:0被當做除數, 比如 10 / 0 ## 最簡單的方法保存圖片到相機膠卷 ```objc UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); /** * 通過UIImageWriteToSavedPhotosAlbum函數寫入圖片完畢后就會調用這個方法 * * @param image 寫入的圖片 * @param error 錯誤信息 * @param contextInfo UIImageWriteToSavedPhotosAlbum函數的最后一個參數 */ - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo { if (error) { [SVProgressHUD showErrorWithStatus:@"圖片保存失敗!"]; } else { [SVProgressHUD showSuccessWithStatus:@"圖片保存成功!"]; } } ``` ## 保存圖片到自定義相冊 ```objc - (IBAction)save { /* PHAuthorizationStatusNotDetermined, 用戶還沒有做出選擇 PHAuthorizationStatusDenied, 用戶拒絕當前應用訪問相冊(用戶當初點擊了"不允許") PHAuthorizationStatusAuthorized 用戶允許當前應用訪問相冊(用戶當初點擊了"好") PHAuthorizationStatusRestricted, 因為家長控制, 導致應用無法方法相冊(跟用戶的選擇沒有關系) */ // 判斷授權狀態 PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; if (status == PHAuthorizationStatusRestricted) { // 因為家長控制, 導致應用無法方法相冊(跟用戶的選擇沒有關系) [SVProgressHUD showErrorWithStatus:@"因為系統原因, 無法訪問相冊"]; } else if (status == PHAuthorizationStatusDenied) { // 用戶拒絕當前應用訪問相冊(用戶當初點擊了"不允許") XMGLog(@"提醒用戶去[設置-隱私-照片-xxx]打開訪問開關"); } else if (status == PHAuthorizationStatusAuthorized) { // 用戶允許當前應用訪問相冊(用戶當初點擊了"好") [self saveImage]; } else if (status == PHAuthorizationStatusNotDetermined) { // 用戶還沒有做出選擇 // 彈框請求用戶授權 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { if (status == PHAuthorizationStatusAuthorized) { // 用戶點擊了好 [self saveImage]; } }]; } } - (void)saveImage { // PHAsset : 一個資源, 比如一張圖片\一段視頻 // PHAssetCollection : 一個相簿 // PHAsset的標識, 利用這個標識可以找到對應的PHAsset對象(圖片對象) __block NSString *assetLocalIdentifier = nil; // 如果想對"相冊"進行修改(增刪改), 那么修改代碼必須放在[PHPhotoLibrary sharedPhotoLibrary]的performChanges方法的block中 [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ // 1.保存圖片A到"相機膠卷"中 // 創建圖片的請求 assetLocalIdentifier = [PHAssetCreationRequest creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier; } completionHandler:^(BOOL success, NSError * _Nullable error) { if (success == NO) { [self showError:@"保存圖片失敗!"]; return; } // 2.獲得相簿 PHAssetCollection *createdAssetCollection = [self createdAssetCollection]; if (createdAssetCollection == nil) { [self showError:@"創建相簿失敗!"]; return; } [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ // 3.添加"相機膠卷"中的圖片A到"相簿"D中 // 獲得圖片 PHAsset *asset = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetLocalIdentifier] options:nil].lastObject; // 添加圖片到相簿中的請求 PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createdAssetCollection]; // 添加圖片到相簿 [request addAssets:@[asset]]; } completionHandler:^(BOOL success, NSError * _Nullable error) { if (success == NO) { [self showError:@"保存圖片失敗!"];; } else { [self showSuccess:@"保存圖片成功!"];; } }]; }]; } /** * 獲得相簿 */ - (PHAssetCollection *)createdAssetCollection { // 從已存在相簿中查找這個應用對應的相簿 PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; for (PHAssetCollection *assetCollection in assetCollections) { if ([assetCollection.localizedTitle isEqualToString:XMGAssetCollectionTitle]) { return assetCollection; } } // 沒有找到對應的相簿, 得創建新的相簿 // 錯誤信息 NSError *error = nil; // PHAssetCollection的標識, 利用這個標識可以找到對應的PHAssetCollection對象(相簿對象) __block NSString *assetCollectionLocalIdentifier = nil; [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ // 創建相簿的請求 assetCollectionLocalIdentifier = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:XMGAssetCollectionTitle].placeholderForCreatedAssetCollection.localIdentifier; } error:&error]; // 如果有錯誤信息 if (error) return nil; // 獲得剛才創建的相簿 return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[assetCollectionLocalIdentifier] options:nil].lastObject; } - (void)showSuccess:(NSString *)text { dispatch_async(dispatch_get_main_queue(), ^{ [SVProgressHUD showSuccessWithStatus:text]; }); } - (void)showError:(NSString *)text { dispatch_async(dispatch_get_main_queue(), ^{ [SVProgressHUD showErrorWithStatus:text]; }); } ``` ## Xcode插件的安裝路徑 ```objc /Users/用戶名/Library/Application Support/Developer/Shared/Xcode/Plug-ins ```