separar para organizar organizador orden mover mac las fotos como carrete cambiar camara ios swift uiscrollview photolibrary

ios - para - Swift: ¿cómo obtener las últimas 3 fotos tomadas de la biblioteca de fotos?



organizar fotos iphone 6 (5)

Detalles

xCode 8.3, Swift 3.1

Código

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 } }

Uso

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 } } }

Muestra completa (collectionView con imágenes de PhotoLibrary)

Info.plist

Añadir a 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 } } } } } }

ColecciónViewCell.swift

import UIKit class CollectionViewCell: UICollectionViewCell { @IBOutlet weak var cellImageView: UIImageView! }

PhotoLibrary.swift

Descrito arriba

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>

Resultado

Necesito obtener y mostrar las últimas 3 fotos tomadas de la biblioteca de fotos en el evento viewDidload sin ningún clic.

Después de este paso, debería obtener otras fotos 3 por 3 cuando desplace la vista de desplazamiento.

¿Sabes la forma correcta de hacer esto con rapidez? Gracias.


Aquí está la respuesta de @Lindsey Scott pero en Objective-C. Estoy poniendo las últimas 9 fotos de Camera Roll en una vista de colección:

-(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]; }


Aquí hay una solución elegante con eficiencia en Swift 4.

En resumen, solicitamos los últimos activos de fotos una vez y luego los convertimos en imagen cuando sea necesario.

Primera biblioteca de fotos de importación:

import Photos

Luego crea una función para obtener las últimas fotos tomadas:

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) }

En su caso, es posible que desee obtener suficientes fotos a la vez (por ejemplo, 50) y luego almacenar el resultado en algún lugar de su controlador de vista:

var latestPhotoAssetsFetched: PHFetchResult<PHAsset>? = nil

En viewDidLoad :

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

Finalmente solicite la imagen en el lugar correcto (por ejemplo, una celda de vista de colección):

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 }

Recuerda agregar una propiedad a tu celular:

class PhotoCell: UICollectionViewCell { var representedAssetIdentifier: String? = nil }


Puede extraer las 3 últimas fotos usando las funciones en el marco de AssetsLibrary . Primero tienes que añadir el framework al proyecto. La siguiente función recupera las 3 últimas fotos y llama al bloque de finalización.

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 función anterior se puede llamar así.

getLatestPhotos(completion: { images in println(images) //Set Images in this block. })


Aquí hay una solución que usa el marco de Photos disponible para dispositivos 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)") } }) } }