Swift-comment obtenir la dernière prise de 3 photos de la photothèque?

j'ai besoin d'obtenir et de montrer enfin pris 3 photos de la bibliothèque de photos sur viewDidload de l'événement sans aucun clics.

après cette étape, je devrais obtenir d'autres photos 3 par 3 Quand je fais défiler le scrollview.

connaissez-vous la bonne façon de le faire avec swift? Grâce.

Sample

21
demandé sur fatihyildizhan 2015-02-01 08:58:20

5 réponses

Photos le cadre est disponible pour les appareils iOS 8+ :

import Photos

class ViewController: UIViewController {

    var images:[UIImage] = []

    func fetchPhotos () {
        // Sort the images by descending creation date and fetch the first 3
        let fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: false)]
        fetchOptions.fetchLimit = 3

        // Fetch the image assets
        let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)

        // If the fetch result isn't empty,
        // proceed with the image request
        if fetchResult.count > 0 {
            let totalImageCountNeeded = 3 // <-- The number of images to fetch
            fetchPhotoAtIndex(0, totalImageCountNeeded, fetchResult)
        }
    }

    // Repeatedly call the following method while incrementing
    // the index until all the photos are fetched
    func fetchPhotoAtIndex(_ index:Int, _ totalImageCountNeeded: Int, _ fetchResult: PHFetchResult<PHAsset>) {

        // Note that if the request is not set to synchronous
        // the requestImageForAsset will return both the image
        // and thumbnail; by setting synchronous to true it
        // will return just the thumbnail
        let requestOptions = PHImageRequestOptions()
        requestOptions.isSynchronous = true

        // Perform the image request
        PHImageManager.default().requestImage(for: fetchResult.object(at: index) as PHAsset, targetSize: view.frame.size, contentMode: PHImageContentMode.aspectFill, options: requestOptions, resultHandler: { (image, _) in
            if let image = image {
                // Add the returned image to your array
                self.images += [image]
            }
            // If you haven't already reached the first
            // index of the fetch result and if you haven't
            // already stored all of the images you need,
            // perform the fetch request again with an
            // incremented index
            if index + 1 < fetchResult.count && self.images.count < totalImageCountNeeded {
                self.fetchPhotoAtIndex(index + 1, totalImageCountNeeded, fetchResult)
            } else {
                // Else you have completed creating your array
                print("Completed array: \(self.images)")
            }
        })
    }
}
41
répondu Lyndsey Scott 2018-01-13 18:02:10

Détails

xCode 8.3, Swift 3.1

Code

import UIKit
import Photos

class PhotoLibrary {

    fileprivate var imgManager: PHImageManager
    fileprivate var requestOptions: PHImageRequestOptions
    fileprivate var fetchOptions: PHFetchOptions
    fileprivate var fetchResult: PHFetchResult<PHAsset>

    init () {
        imgManager = PHImageManager.default()
        requestOptions = PHImageRequestOptions()
        requestOptions.isSynchronous = true
        fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)]
        fetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
    }

    var count: Int {
        return fetchResult.count
    }

    func setPhoto(at index: Int, completion block: @escaping (UIImage?)->()) {

        if index < fetchResult.count  {
            imgManager.requestImage(for: fetchResult.object(at: index) as PHAsset, targetSize: UIScreen.main.bounds.size, contentMode: PHImageContentMode.aspectFill, options: requestOptions) { (image, _) in
                block(image)
            }
        } else {
            block(nil)
        }
    }

    func getAllPhotos() -> [UIImage] {

        var resultArray = [UIImage]()
        for index in 0..<fetchResult.count {
            imgManager.requestImage(for: fetchResult.object(at: index) as PHAsset, targetSize: UIScreen.main.bounds.size, contentMode: PHImageContentMode.aspectFill, options: requestOptions) { (image, _) in

                if let image = image {
                    resultArray.append(image)
                }
            }
        }
        return resultArray
    }
}

Utilisation

 var photoLibrary = PhotoLibrary()
 // Number of all photos
 photoLibrary.count
 // Get photo
 self.photoLibrary.setPhoto(at: indexPath.row) { image in
      if let image = image {
              DispatchQueue.main.async {
                    imageView.image = image
              }
      }
 }

totalité de l'Échantillon (collectionView avec des images de PhotoLibrary)

Info.plist

ajouter à L'Info.plist

<key>NSPhotoLibraryUsageDescription</key>
<string>{bla-bla-bla}</string>

ViewController.swift

import UIKit
import Photos

class ViewController: UIViewController {

    @IBOutlet weak var collectionView: UICollectionView!
    @IBOutlet weak var collectionViewFlowLayout: UICollectionViewFlowLayout!

    fileprivate var photoLibrary: PhotoLibrary!
    fileprivate var numberOfSections = 0

    override func viewDidLoad() {
        initCollectionView()
        PHPhotoLibrary.requestAuthorization { [weak self] result in
            if let _self = self {
                if result == .authorized {
                    _self.photoLibrary = PhotoLibrary()
                    _self.numberOfSections = 1
                     DispatchQueue.main.async {
                        _self.collectionView.reloadData()
                    }
                }
            }
        }
    }
}

extension ViewController: UICollectionViewDataSource {

    fileprivate var numberOfElementsInRow: Int {
        return 4
    }

    var sizeForCell: CGSize {
        let _numberOfElementsInRow = CGFloat(numberOfElementsInRow)
        let allWidthBetwenCells = _numberOfElementsInRow == 0 ? 0 : collectionViewFlowLayout.minimumInteritemSpacing*(_numberOfElementsInRow-1)
        let width = (collectionView.frame.width - allWidthBetwenCells)/_numberOfElementsInRow
        return CGSize(width: width, height: width)
    }

    func initCollectionView() {
        collectionView.dataSource = self
        collectionView.delegate = self
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return numberOfSections
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return photoLibrary.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
        return cell
    }

}

extension ViewController: UICollectionViewDelegateFlowLayout {

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

    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        let cell = cell as! CollectionViewCell
        cell.cellImageView.image = nil
        DispatchQueue.global(qos: .background).async {
            self.photoLibrary.setPhoto(at: indexPath.row) { image in
                if let image = image {
                    DispatchQueue.main.async {
                        cell.cellImageView.image = image
                    }
                }
            }
        }
    }
}

CollectionViewCell.swift

import UIKit
class CollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var cellImageView: UIImageView!
}

PhotoLibrary.swift

Décrit ci-dessus

Main.storyboard

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12118" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12086"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_28259961" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="IZe-8T-NdF">
                                <rect key="frame" x="0.0" y="20" width="375" height="647"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                <collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="2" minimumInteritemSpacing="2" id="DNv-oA-G6j">
                                    <size key="itemSize" width="100" height="100"/>
                                    <size key="headerReferenceSize" width="0.0" height="0.0"/>
                                    <size key="footerReferenceSize" width="0.0" height="0.0"/>
                                    <inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
                                </collectionViewFlowLayout>
                                <cells>
                                    <collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="CollectionViewCell" id="FND-c4-nYC" customClass="CollectionViewCell" customModule="stackoverflow_28259961" customModuleProvider="target">
                                        <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
                                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                                        <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
                                            <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
                                            <autoresizingMask key="autoresizingMask"/>
                                            <subviews>
                                                <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="FA0-5K-Pxh">
                                                    <rect key="frame" x="0.0" y="0.0" width="100" height="100"/>
                                                </imageView>
                                            </subviews>
                                        </view>
                                        <color key="backgroundColor" red="0.82995896879999997" green="0.82995896879999997" blue="0.82995896879999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <constraints>
                                            <constraint firstItem="FA0-5K-Pxh" firstAttribute="top" secondItem="FND-c4-nYC" secondAttribute="top" id="0WE-w2-xTC"/>
                                            <constraint firstAttribute="trailing" secondItem="FA0-5K-Pxh" secondAttribute="trailing" id="7rj-8k-UrU"/>
                                            <constraint firstItem="FA0-5K-Pxh" firstAttribute="leading" secondItem="FND-c4-nYC" secondAttribute="leading" id="ofw-aq-B79"/>
                                            <constraint firstAttribute="bottom" secondItem="FA0-5K-Pxh" secondAttribute="bottom" id="ogx-56-qNt"/>
                                        </constraints>
                                        <connections>
                                            <outlet property="cellImageView" destination="FA0-5K-Pxh" id="DE1-DT-Oik"/>
                                        </connections>
                                    </collectionViewCell>
                                </cells>
                            </collectionView>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                        <constraints>
                            <constraint firstAttribute="trailing" secondItem="IZe-8T-NdF" secondAttribute="trailing" id="1W1-Fl-ZL8"/>
                            <constraint firstItem="IZe-8T-NdF" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="9QC-93-vwd"/>
                            <constraint firstItem="IZe-8T-NdF" firstAttribute="bottom" secondItem="wfy-db-euE" secondAttribute="top" id="BEF-2W-Otd"/>
                            <constraint firstItem="IZe-8T-NdF" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="isg-PJ-70G"/>
                        </constraints>
                    </view>
                    <connections>
                        <outlet property="collectionView" destination="IZe-8T-NdF" id="z6G-PD-d44"/>
                        <outlet property="collectionViewFlowLayout" destination="DNv-oA-G6j" id="y8U-CI-3CD"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="133.59999999999999" y="129.98500749625188"/>
        </scene>
    </scenes>
</document>

Résultat

enter image description here

7
répondu Vasily Bodnarchuk 2017-04-01 20:52:42

vous pouvez extraire les 3 dernières photos en utilisant des fonctions dans le AssetsLibrary cadre. Vous devez d'abord ajouter le cadre du projet. La fonction suivante récupère les 3 dernières photos et appelle le bloc d'achèvement.

import AssetsLibrary

func getLatestPhotos(completion completionBlock : ([UIImage] -> ()))   {
    let library = ALAssetsLibrary()
    var count = 0
    var images : [UIImage] = []
    var stopped = false

    library.enumerateGroupsWithTypes(ALAssetsGroupSavedPhotos, usingBlock: { (group,var stop) -> Void in

        group?.setAssetsFilter(ALAssetsFilter.allPhotos())

        group?.enumerateAssetsWithOptions(NSEnumerationOptions.Reverse, usingBlock: {
            (asset : ALAsset!, index, var stopEnumeration) -> Void in

            if (!stopped)
            {
                if count >= 3
                {

                    stopEnumeration.memory = ObjCBool(true)
                    stop.memory = ObjCBool(true)
                    completionBlock(images)
                    stopped = true
                }
                else
                {
                    // For just the thumbnails use the following line.
                    let cgImage = asset.thumbnail().takeUnretainedValue()

                    // Use the following line for the full image.
                    let cgImage = asset.defaultRepresentation().fullScreenImage().takeUnretainedValue()

                    if let image = UIImage(CGImage: cgImage) {
                        images.append(image)
                        count += 1
                    }
                }
            }

        })

        },failureBlock : { error in
            println(error)
    })
}

La fonction ci-dessus peut être appelé comme ceci

getLatestPhotos(completion: { images in
     println(images)
     //Set Images in this block.
})
6
répondu rakeshbs 2015-02-01 11:44:04

Voici la réponse de @Lindsey Scott mais dans Objective-C. je mets les 9 dernières photos de Camera Roll dans une vue de collection:

-(void)fetchPhotoFromEndAtIndex:(int)index{

PHImageRequestOptions *options = [[PHImageRequestOptions alloc]init];
options.synchronous = YES;
PHFetchOptions *fetchOptions = [[PHFetchOptions alloc]init];
fetchOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];

PHFetchResult *photos = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:fetchOptions];
if (photos) {
    [[PHImageManager defaultManager] requestImageForAsset:[photos objectAtIndex:photos.count -1 -index] targetSize:CGSizeMake(self.collectionView.frame.size.width/3, self.collectionView.frame.size.height/3) contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *result, NSDictionary *info) {
        [self.imagesArray addObject:result];

        if (index + 1 < photos.count && self.imagesArray.count < 9) {
            [self fetchPhotoFromEndAtIndex:index + 1];
        }
    }];
}

[self.collectionView reloadData];

}
5
répondu Boris Nikolić 2015-07-01 17:01:35

Voici une solution élégante et efficace pour Swift 4.

en bref, nous demandons les dernières ressources photo Une fois, puis les convertir en image si nécessaire.

tout d'Abord importer les Photos de la Bibliothèque:

import Photos

Ensuite créer une fonction pour récupérer les dernières photos prises:

func fetchLatestPhotos(forCount count: Int?) -> PHFetchResult<PHAsset> {

    // Create fetch options.
    let options = PHFetchOptions()

    // If count limit is specified.
    if let count = count { options.fetchLimit = count }

    // Add sortDescriptor so the lastest photos will be returned.
    let sortDescriptor = NSSortDescriptor(key: "creationDate", ascending: false)
    options.sortDescriptors = [sortDescriptor]

    // Fetch the photos.
    return PHAsset.fetchAssets(with: .image, options: options)

}

Dans votre cas vous pouvez chercher assez de photos à la fois (par exemple 50), puis stocker le résultat quelque part dans votre vue contrôleur:

var latestPhotoAssetsFetched: PHFetchResult<PHAsset>? = nil

viewDidLoad:

self.latestPhotoAssetsFetched = self.fetchLatestPhotos(forCount: 50)

enfin, demandez l'image au bon endroit (par exemple, une cellule de vue collection):

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    /*
     ...your code to configure the cell...
     */

    // Get the asset. If nothing, return the cell.
    guard let asset = self.latestPhotoAssetsFetched?[indexPath.item] else {
        return cell
    }
    // Here we bind the asset with the cell.
    cell.representedAssetIdentifier = asset.localIdentifier
    // Request the image.
    PHImageManager.default().requestImage(for: asset,
                                   targetSize: cell.imageView.frame.size,
                                  contentMode: .aspectFill,
                                      options: nil) { (image, _) in
        // By the time the image is returned, the cell may has been recycled.
        // We update the UI only when it is still on the screen.
        if cell.representedAssetIdentifier == asset.localIdentifier {
            cell.imageView.image = image
        }
    }
    return cell
}

n'oubliez pas d'ajouter une propriété à votre cellule:

class PhotoCell: UICollectionViewCell {
    var representedAssetIdentifier: String? = nil
}
5
répondu Tim Chen 2018-01-15 10:25:01