33 votes

PHPhotoLibrary s'est planté lors de la récupération de placeholderForCreatedAsset

J'essaie de mettre une image dans un album personnalisé avec ce code :

PHAssetCollection *album = [self getMyAlbum];
UIImage *image = [self getMyImage];

[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

    PHObjectPlaceholder * placeHolder = createAssetRequest.placeholderForCreatedAsset;

    PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];

    if(placeHolder){
        [albumChangeRequest addAssets:@[ placeHolder ]];
    }

} completionHandler:^(BOOL success, NSError *error) {
    //doesen't matter
}];

Ainsi, je reçois de nombreuses erreurs dans les journaux des utilisateurs dans cette ligne createAssetRequest.placeholderForCreatedAsset

comme

1 CoreFoundation __exceptionPreprocess + 1245624

2 libobjc.A.dylib objc_exception_throw + 34136

3 Photos __48- [PHChangeRequestHelper generateUUIDIfNecessary]_block_invoke + 116552

2 libdispatch.dylib _dispatch_semaphore_wait_slow + 79828

3 Photos - [PHChangeRequestHelper generateUUIDIfNecessary] + 115992

4 Photos - [PHAssetCreationRequest placeholderForCreatedAsset] + 244020

donc [PHChangeRequestHelper generateUUIDIfNecessary] donnez-moi un accident.

Je ne vois cela que sur iOS > 10 et je ne peux pas reproduire ce phénomène dans le simulateur.

Qu'est-ce que c'est ? Comment le réparer ?

0 votes

Avez-vous réussi à trouver un problème ?

0 votes

Ce bogue apparaît également lorsque je sauvegarde la photo sans l'insérer dans la collection. Comme ceci : var placeholderAssetBlock : PHObjectPlaceholder ? PHPhotoLibrary.shared().performChanges({ let asset = PHAssetChangeRequest.creationRequestForAsset(from : photo) placeholderAssetBlock = asset.placeholderForCreatedAsset }

0 votes

Quelle est l'exception qui est levée ?

2voto

pravir Points 8

Essayez d'utiliser ceci. J'espère que c'est ce que vous cherchez.

import UIKit
import Photos

protocol CameraRollViewControllerProtocol: class {
    func displayTappedImage(displayImage: UIImage)
    func scrollToCameraButtonTapped()
}

class CameraRollViewController:  UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

    @IBOutlet var collectionView: UICollectionView!

    var images = [PHAsset]()
    var displayImage: UIImage!
    // used to specify the target size of the thumbnails of images in cameraRoll
    // In iPhone6 images of target size 100.0 were successfully obtained and in iPhone 6plus images of 400.0 were obtained successfully; for other target size a nil image was obtained.
    var thumbImageSize: Double!
    var targetSize: CGSize!
    weak var delegate: CameraRollViewControllerProtocol!

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.contentInset = UIEdgeInsets(top: 24.0, left: 24.0, bottom: 24.0, right: 24.0)
//        if UIScreen.main.bounds.width > 375 {
//            thumbImageSize = 100.0
//        } else {
            thumbImageSize = 100.0
//        }

    }

    override func viewWillAppear(_ animated: Bool) {

        collectionView.isUserInteractionEnabled = true

        self.navigationController?.navigationBar.titleTextAttributes = [ NSAttributedStringKey.foregroundColor: UIColor.cameraRollNavigationBarTitle, NSAttributedStringKey.font: UIFont.gothamRoundedMedium20!]

        checkPermission { (success) in
            if success {
                OperationQueue.main.addOperation({
                    self.getImages()
                })
            }
        }
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    // MARK: - UICollectionViewDataSource
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return images.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {            
            if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "galleryPhotoCell", for: indexPath) as? CameraRollCell {

                let asset = images[indexPath.row]
                let manager = PHImageManager.default()

                if cell.tag != 0 {
                    manager.cancelImageRequest(PHImageRequestID(cell.tag))
                }

                cell.tag = Int(manager.requestImage(for: asset,
                                                    targetSize: CGSize(width: thumbImageSize, height: thumbImageSize),
                                                    contentMode: .aspectFill,
                                                    options: nil) { (result, _) in

                                                        if result != nil {
                                                            cell.imageView?.image = result
                                                        } else {
                                                            cell.imageView.image = #imageLiteral(resourceName: "cloud-Image")
                                                        }
                })
                return cell
            }
            else {
                return UICollectionViewCell()
            }
    }

    @IBAction func CameraButtonTapped(_ sender: Any) {
        delegate.scrollToCameraButtonTapped()
    }
}

extension CameraRollViewController {

    func getImages() {

        if images.count > 0 {
            images.removeAll()
        }

        let assets = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: nil) //fetchOptions)//nil)

        assets.enumerateObjects({ (object, count, stop) in
            self.images.append(object)
        })
        self.images.reverse()
        self.collectionView.reloadData()
    }

    func checkPermission( completionHandler:@escaping (_ success:Bool)->()) {

        PHPhotoLibrary.requestAuthorization({ (status:PHAuthorizationStatus) in
            if status == .authorized {
                completionHandler(true)
            } else {
                completionHandler(false)
            }
        })
    }
}

extension CameraRollViewController {

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 96.0, height: 96.0)
    }

    func collectionView(_ collectionView: UICollectionView, layout
        collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 20.0
    }
}

extension CameraRollViewController {

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

        // check size of Asset before loading it

        let asset = images[indexPath.row]
        let resources = PHAssetResource.assetResources(for: asset)

        var sizeOnDisk: Int64? = 0

        if let resource = resources.first {
            let unsignedInt64 = resource.value(forKey: "fileSize") as? CLong
            sizeOnDisk = Int64(bitPattern: UInt64(unsignedInt64!))
        }

        LogManager.logInfo("SIZE OF IMAGE: \(converByteToHumanReadable(sizeOnDisk!))")

        let imageSizeString = sizeOnDisk!/1048576
        LogManager.logInfo(" SIZE OF IMAGE (1048576): \(imageSizeString)")

        if imageSizeString > 2 {

            targetSize = CGSize.init(width: 1000.0, height: 1000.0)

        } else {
            targetSize = PHImageManagerMaximumSize
        }

        let manager = PHImageManager.default()

        let options: PHImageRequestOptions = PHImageRequestOptions()
        //options.resizeMode = .exact
        options.deliveryMode = .highQualityFormat //.opportunistic
        //options.resizeMode = .exact

        manager.requestImage(for: asset,
                             targetSize: targetSize, //CGSize(width: 375.0, height: 667.0)  ,
                             contentMode: .aspectFit,
                             options: options) { (result, info) in

                                if (info![PHImageResultIsInCloudKey] != nil) {
                                    print("\n\nIS IN CLOUD: \(info![PHImageResultIsInCloudKey] as! Bool)")
                                }

                                guard info![PHImageResultIsDegradedKey] as! Bool == false else {
                                    LogManager.logInfo("Image is degraded")
                                    return
                                }
                                if let image = result {
                                    print("\n\n*********************************==========Local Image*********************************==========\n\n")
                                    let imageData: NSData = NSData(data: UIImageJPEGRepresentation((image), 1)!)

                                    let frameImageData: NSData = NSData(data: UIImageJPEGRepresentation((image), 0.1)!)
                                    let frameImageCompressed: UIImage = UIImage(data: frameImageData as Data)!

                                    LogManager.logInfo(" SIZE OF IMAGE LOADED EARLIER : \(image.size); \(imageData.length/1048576).\(imageData.length%1048576)")
                                    LogManager.logInfo("SIZE OF IMAGE LOADED NOW : \(frameImageCompressed.size); \(frameImageData.length/1048576).\(frameImageData.length%1048576)")

                                    self.displayImage = image
                                    self.delegate.displayTappedImage(displayImage: self.displayImage)
                                } else {

//                                    if (self.getImage(asset: asset)) != nil {
//                                        self.displayImage = self.getImage(asset: asset) //image
//                                        self.delegate.displayTappedImage(displayImage: self.displayImage)

//UNCOMMENT LATER
                                    print("\n\n*********************************==========Cloud Image*********************************==========\n\n")
                                    let options = PHImageRequestOptions()
                                    options.deliveryMode = .highQualityFormat
                                    options.isSynchronous = true
                                    //options.isNetworkAccessAllowed = true
                                    options.progressHandler = { (progress, error, stop, info) in
                                        print("PROGRESS: \(progress)") //.debug("\(progress)")
                                    }
                                    options.version = PHImageRequestOptionsVersion.original

                                    PHImageManager.default().requestImage(for: asset, targetSize:  UIScreen.main.bounds.size , contentMode: .aspectFill, options: options) { (image, info) in
                                        if image !=  nil {

                                            //print(info!["PHImageResultIsInCloudKey"] as! Bool)
                                            //compressedImageData = self.compressImage(image: image!)
                                            self.displayImage = image
                                            self.delegate.displayTappedImage(displayImage: self.displayImage)
                                        } else{
                                            // request image with size 200x200
                                            print("MUST NOT EXECUTE")
                                            print("\n\n*********************************==========Local THUMBNAIL  Image*********************************==========\n\n")
                                            let options: PHImageRequestOptions = PHImageRequestOptions()
                                            //options.resizeMode = .exact
                                            options.deliveryMode = .highQualityFormat //.opportunistic
                                            //options.resizeMode = .exact

                                            PHImageManager.default().requestImage(for: asset, targetSize: CGSize.init(width: 150, height: 150), contentMode: .aspectFill, options: options) { (image, info) in
                                                if image !=  nil {

                                                    self.displayImage = image
                                                    self.delegate.displayTappedImage(displayImage: self.displayImage)
                                                }
                                            }
                                        }
                                    }
//UNCOMMENT LATER
//                                    }
//                                    else {

                                    // show popup saying download the image from icloud in this device as it's just a thumbnail
//                                    self.createAlert(title: "Photo Not Accessible", message: "Please download it from iCloud to use it.")

//                                    }

                                }
        }
        collectionView.isUserInteractionEnabled = false
    }
}

extension CameraRollViewController {

    func createAlert(title: String, message: String) {

        let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)

        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: { (action) in
            alert.dismiss(animated: true, completion: nil)
            LogManager.logInfo("OK Pressed")
            self.collectionView.isUserInteractionEnabled = true
        }))
        self.present(alert, animated: true, completion: nil)
    }

    func converByteToHumanReadable(_ bytes:Int64) -> String {

        let formatter:ByteCountFormatter = ByteCountFormatter()
        formatter.countStyle = .binary
        return formatter.string(fromByteCount: Int64(bytes))
    }

    func getImage(asset: PHAsset) -> UIImage?  {

        var assetImage: UIImage?
        let options = PHImageRequestOptions()
        options.isSynchronous = true
        options.isNetworkAccessAllowed = true

        PHImageManager.default().requestImage(for: asset, targetSize: UIScreen.main.bounds.size, contentMode: .aspectFill, options: options) { (image, info) in
            assetImage = image
        }

        return assetImage
    }

}

1voto

Bhavesh Patel Points 167

Veuillez essayer le code ci-dessous.

__block NSString* tempPath;
// Add it to the photo library
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

    if (self.assetCollection) {
        PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
        [assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
    }
    tempPath = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];
} completionHandler:^(BOOL success, NSError *error) {
    PHFetchResult* assetResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[tempPath] options:nil];
    if (!success) {
        NSLog(@"Error creating asset: %@", error);
    } else {
        PHFetchResult* assetResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[tempPath] options:nil];
        PHAsset *asset = [assetResult firstObject];
        [[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
            UIImage* newImage = [UIImage imageWithData:imageData];
            self.imgView.image = newImage;
        }];
    }
}];

1voto

mayanksengar Points 255

Vous pouvez utiliser le code suivant.

`#pragma mark - Create Custom Album name

-(void)saveImageWithAlbumNameAndImage:(UIImage *)image
{
__block PHFetchResult *photosAsset;
__block PHAssetCollection *collection;
__block PHObjectPlaceholder *placeholder;

// Find the album
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc] init];
fetchOptions.predicate = [NSPredicate predicateWithFormat:@"title = %@", MKCustomPhotoAlbumName];
collection = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                                                      subtype:PHAssetCollectionSubtypeAny
                                                      options:fetchOptions].firstObject;
// Create the album
if (!collection)
{
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        PHAssetCollectionChangeRequest *createAlbum = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:MKCustomPhotoAlbumName];

        placeholder = [createAlbum placeholderForCreatedAssetCollection];
    } completionHandler:^(BOOL success, NSError *error) {
        if (success)
        {
            PHFetchResult *collectionFetchResult = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[placeholder.localIdentifier]
                                                                                                        options:nil];
            collection = collectionFetchResult.firstObject;
        }
    }];
}

// Save to the album
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
    PHAssetChangeRequest *assetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
    placeholder = [assetRequest placeholderForCreatedAsset];
    photosAsset = [PHAsset fetchAssetsInAssetCollection:collection options:nil];
    PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection
                                                                                                                  assets:photosAsset];
    [albumChangeRequest addAssets:@[placeholder]];
} completionHandler:^(BOOL success, NSError *error) {
    if (success)
    {
        NSString *UUID = [placeholder.localIdentifier substringToIndex:36];
        NSLog(@"UUID : %@",UUID);
    }
    else
    {
        NSLog(@"%@", error);
    }
}];
}`

Ici MKCustomPhotoAlbumName est la macro et a placé le nom de l'album que vous vouliez créer.

Comme vous pouvez l'observer dans le code, votre image est sauvegardée dans l'album habituel créé dans l'application photos de l'iPhone, et s'il est déjà créé, elle est sauvegardée directement dans cet album.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X