I need to combine PHAsset and UIImage in UICOllectionView
UIImage get from string and converter to image
PHAsset get from device album
var assetCollection: PHAssetCollection!
var photosAsset: PHFetchResult<AnyObject>!
var assetThumbnailSize: CGSize!
var downloadImages: [String] = []
In cellForItemAt I try:
let indexP = indexPath.row
let asset: PHAsset = self.photosAsset[indexP] as! PHAsset
PHImageManager.default().requestImage(for: asset, targetSize: self.assetThumbnailSize, contentMode: .aspectFill, options: nil, resultHandler: {(result, info)in
if result != nil {
let download = self.downloadImages[indexP]
let downloadIm = "http://...\(download)"
cell.albumImage.downloadImage(from: downloadIm)
cell.albumImage.image = result
}
})
return cell
how can I combine downloadIm and result to show in UIImageView on collectionView?
downloadImage is :
extension UIImageView {
func downloadImage(from imgURL: String!) {
let url = URLRequest(url: URL(string: imgURL)!)
let task = URLSession.shared.dataTask(with: url) {
(data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}
task.resume()
}
}
I am facing this same problem in one of my project. Need to handle both UIImage and string url in same UICollectionView. You can implement similar to this;
// first create struct with datatypes
struct imageItem {
var stringImageURL:String
var imageGallery:UIImage
}
var array_ImagesList: [imageItem] = []
// then you can append image or string url wherever you want as per functionality
// inside UIImagePickerController Delegates I am append UIImage
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage
{
array_ImagesList.append(imageItem.init(stringImageURL: "",
imageGallery: image))
}
picker.dismiss(animated: true, completion: nil);
}
// and in some other function I want to append image from server URL
func addImagesFromServer() {
let imageUrl: String = "htps://someserver/image.png"
array_ImagesList.append(imageItem.init(stringImageURL: imageUrl!,
imageGallery:""))
collectionView.reloadData()
}
//MARK: CollectionView DataSources & Delegates
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return array_ImagesList.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt
indexPath: IndexPath) -> UICollectionViewCell{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier:
"kGalleryImageCell", for: indexPath as IndexPath) as!
AddImagesCollectionViewCell
// check to show image or from url here
// for image
cell.imageView.image = array_ImagesList[indexPath.row].imageGallery
// from image url
let stringUrlImage =
array_ImagesList[indexPath.row].stringImageURL
let placeholderImage = UIImage(named:
"logoCategorySmallIcon")!
if(stringUrlImage.isEmpty){
cell.imageGalleryCell.image = placeholderImage
}else{
var stringImageUrl = imageHostAPI+"\(stringUrlImage)"
stringImageUrl =
stringImageUrl.addingPercentEncoding(withAllowedCharacters:
CharacterSet.urlQueryAllowed)!
let url = URL(string: stringImageUrl)
cell.imageView.sd_setShowActivityIndicatorView(true)
cell.imageView.sd_setIndicatorStyle(.gray)
cell.imageView.sd_setImage(with: url!,
placeholderImage: placeholderImage)
}
return cell
}
Related
I am new to parsing json in Swift and in my app I created an inbox. In this inbox, I load a profile image and a name in every cell. I found an API online with video game characters and their images for a test. However, when the json is parsed and put in the cell, the app loads the cells and occasionally the images move around to other cells or duplicate. I have seen this posted before, but none of the past answers have solved my solution.
Here is what it looked like when it loaded which is incorrect
Here is what happened one second later which is still incorrect and you can see duplication
This is my CollectionViewCell.Swift File
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageCell: UIImageView!
#IBOutlet weak var dateCell: UILabel!
override func prepareForReuse() {
self.imageCell.image = nil
self.imageCell.setNeedsDisplay() // tried adding after some recommendations
self.setNeedsDisplay() // tried adding after some recommendations
super.prepareForReuse()
}
}
This is my main inbox view controller extension for the image I found online
extension UIImageView {
func downloadedFrom(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
self.image = image
}
}.resume()
}
func downloadedFrom(link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloadedFrom(url: url, contentMode: mode)
}
}
This is the rest of the inbox view controller code (deleted unrelated code from it for the purpose of this question)
class InboxViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var inboxCollection: UICollectionView!
struct Hero: Decodable {
let localized_name: String
let img: String
}
var heroes = [Hero]()
override func viewDidLoad() {
super.viewDidLoad()
inboxCollection.dataSource = self
let url = URL(string: "https://api.opendota.com/api/heroStats")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil {
do {
self.heroes = try JSONDecoder().decode([Hero].self, from: data!)
}catch {
print("Parse Error")
}
DispatchQueue.main.async {
self.inboxCollection.reloadData()
}
}
}.resume()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.heroes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) as! CollectionViewCell
cell.dateCell.text = heroes[indexPath.row].localized_name.capitalized
let defaultLink = "https://api.opendota.com"
cell.imageCell.image = nil
let completelink = defaultLink + heroes[indexPath.row].img
cell.imageCell.image = nil
cell.imageCell.downloadedFrom(link: completelink)
cell.imageCell.clipsToBounds = true
cell.imageCell.layer.cornerRadius = cell.imageCell.frame.height / 2
cell.imageCell.contentMode = .scaleAspectFill
cell.imageCell.image = nil
return cell
}
You shouldn't be setting UIImageView's image within the UIImageView. In fact, don't even create two separate methods - you have no good reason to. Download each image in your UIViewController and use a dictionary to map a hero's name to their image like so:
var heroImages = [String:URL]()
func getDataFromUrl(url: URL, completion: #escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url) { data, response, error in
completion(data, response, error)
}.resume()
}
func getImages() {
for hero in self.heroes {
let url = NSURL(string: hero)
getDataFromURL(url: url, completion: {(data: Data?, response:URLResponse?, error: Error?) in
if (data != nil) {
image = UIImage(data: data)
heroImages[hero] = image }
if (heroImages.count == self.heroes.count) {
// We've downloaded all the images, update collection view
DispatchQueue.main.async { self.collectionView.reloadData() }
}
}
}
I want to download images from server and display in UICollectionView. First time when user connect with internet than all images will download in background and display from local directory when user is offline. I am using alamofire to download the images. Firstly i am checking existence of image, if it is not already dowloaded than i download it. The problem is that the album is not showing when it is already downloaded. I do not know how. Here is my code:
import UIKit
import Alamofire
var myurl : URL!
var imageName : String!
var bool = false
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if (background_imageurl.count > 0) {
if Reachability.isConnectedToNetwork() == true{
downloadAllImages(urlArray : background_imageurl)
}
}
}
func downloadAllImages(urlArray:[String])->Void{
for i in 0 ..< urlArray.count {
let fullName = urlArray[i]
let fullNameArr = (fullName as AnyObject).components(separatedBy: "//")
let imgname = fullNameArr[1]
let tempimgname = imgname
let tempimgname2 = tempimgname.components(separatedBy: "/")
imageName = tempimgname2[4]
myurl = docsurl.appendingPathComponent("\("guidedCellImages")/\(self.imageName!)")
print("\n myurl", myurl)
if FileManager.default.fileExists(atPath: myurl.path, isDirectory: &bool),bool.boolValue {
print("\n fileExists", myurl.path)
}else{
downloadFile(url: urlArray[i] as! String)
}
}
}
func downloadFile(url: String)->Void{
let destination: (URL, HTTPURLResponse) -> (URL, DownloadRequest.DownloadOptions) = {
(temporaryURL, response) in
let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let filePath = directoryURL?.appendingPathComponent("\("guidedCellImages")/\(self.imageName!)")
return (filePath!, [.removePreviousFile, .createIntermediateDirectories])
}
let utilityQueue = DispatchQueue.global(qos: .utility)
print("url", url)
Alamofire.download(
url,
method: .get,
encoding: JSONEncoding.default,
to: destination)
.downloadProgress(queue: utilityQueue) { progress in
}
.response(completionHandler: { (DefaultDownloadResponse) in
if (self.urlArray.count > 0){
self.urlArray.removeFirst()
print("self.urlArray", self.urlArray.count)
}
if DefaultDownloadResponse.response?.statusCode == 200 {
print(DefaultDownloadResponse.destinationURL!)
}
})
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CollectionViewCell
myurl = docsurl.appendingPathComponent("\("guidedCellImages")")
if FileManager.default.fileExists(atPath: myurl.path, isDirectory: &bool),bool.boolValue {
let directoryContents = try! fileManager.contentsOfDirectory(at: myurl, includingPropertiesForKeys: nil)
print("\ndirectoryContents", directoryContents)
for imageURL in directoryContents where imageURL.pathExtension == "png" {
if let image = UIImage(contentsOfFile: imageURL.path) {
cell.tab1GuidedimageView.image = image
} else {
fatalError("Can't create image from file \(imageURL)")
}
}
}else{
if (background_imageurl.count > 0 ){
cell.tab1imageView.sd_setImage(with: URL(string: background_imageurl[indexPath.row]), placeholderImage: UIImage(named: "background"),options: .refreshCached)
}
}
return cell
}
Try this below procedure, this might helps you
struct Animal{
var name: String
var url: String
var image: UIImage?
}
extension Animal{
init(info: [String: String]) {
self.name = info["name"]!
self.url = info["url"]!
}
}
class CollectionViewCell{
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var label: UILabel!
}
class ViewController: UIViewController{
var animals = [Animal]()
override func viewDidLoad(){
super.viewDidLoad()
}
func getAnimals(){
// hit server api to get the images
// assuming that the following json is coming from server
let jsonResponse = [["name":"Dog","url":"https://animals.com/images/image/dog.jpeg"],
["name":"Lion","url":"https://animals.com/images/image/lion.jpeg"],
["name":"Tiger","url":"https://animals.com/images/image/tiger.jpeg"],
["name":"Horse","url":"https://animals.com/images/image/horse.jpeg"],
["name":"Elephant","url":"https://animals.com/images/image/elephant.jpeg"]]
for animal in jsonResponse {
let lAnimal = Animal(info: animal)
// get locally saved image initially from collectionview cell, if it is existed then add it to your response model
let directoryURL = getDocumentsDirectory()
let imageURL = URL(string: lAnimal.url)
let imagePath = directoryURL.appendingPathComponent("animals/\(imageURL.lastPathComponent)")
if fileManager.fileExistsAtPath(imagePAth){
// pass locallay saved image path
lAnimal.image = UIImage(contentsOfFile: imagePAth)
}else{
print("image needs to be downloaded")
}
}
}
func getDocumentsDirectory() -> URL {
let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
return directoryURL!
}
}
extension ViewController: UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.animals.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell : CollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "reuseIdentifier", for: indexPath) as! CollectionViewCell
let animal = self.animals[indexPath.row]
cell.label.text = animal.name
if let animalImage = animal.image{
//if animal image existis from local them simply display it
cell.imageView.image = animalImage
}else{
//download image from server using simple url task or by using alamofire
let imageURL = URL(string: animal.url)!
let task = URLSession.shared.dataTask(with: imageURL, completionHandler: { (data, response, error) in
if let lData = data {
let image = UIImage(data: lData)
cell.imageView.image = image
let filename = getDocumentsDirectory().appendingPathComponent("animals/\(imageURL.lastPathComponent)")
try? lData.write(to: filename)
//update local data model object
animal.image = image
}
if let lError = error{
/** Handle session error ..................... **/
}
})
}
return cell
}
}
The issue seems with self.imageName. When you are downloading image, the imageName Would have changed in the for loop. Make sure to generate the image name each time from url. while downloading and saving and also while checking.
In fact you can change the scope of imageName variable from global to local.
Recommended is write function to get the image name to avoid redundancy.
EDIT
The guidedCellImages folder must exists, just by adding guidedCEllImages will not create the folder automatically. make sure to add slash (/) before the guidedCellImages
Please check how to create the folder inside document directory here
Hope it helps..!!!
Try this code
func downloadFile(url: String)-> Void {
let directoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
let filePath = directoryURL?.appendingPathComponent("\("guidedCellImages")/\(self.imageName!)")
let data = NSData(contentsOf: URL(string: url)!)
data?.write(toFile: filePath, atomically: true)
}
I have a UICollectionViewCell and Inside that there is a imageView. My requirement is that I am getting Images Url from My_API and I want to download the Images from these Images Url and want to show them into a collectionViewCell imageView.
First thing is that how can I download the images from url I mean Which method is best and how to use NSCache in CollectionViewCell for images (in CellForRowAtIndexPath method).
Here is my code:
//MARK : DataSource
extension BrandImagesTableCell : UICollectionViewDataSource,UICollectionViewDelegateFlowLayout
{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if 0 != arrImages.count {
return self.arrImages.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BrandImagesCell", for: indexPath) as! BrandImagesCell
//let StrUrl = NSURL(string: self.arrImages[indexPath.row])! as URL
let urlPath: String = self.arrImages[indexPath.row]
let StrUrl: NSURL = NSURL(string: urlPath)!
if 0 != arrImages.count
{
cell.brandImage.downloadedFrom(url: StrUrl as URL)//, contentMode: .scaleToFill)
//cell.backgroundColor = UIColor.lightGray
}
return cell
}
}
In self.arrImages I have Images url.
And here is my download image method:
//Download Image from server.
extension UIImageView {
func downloadedFrom(url: URL) { //, contentMode mode: UIViewContentMode = .scaleAspectFit) {
//contentMode = mode
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { () -> Void in
self.image = image
}
}.resume()
}
}
So I want to know which method is better to download images, and do I have to use thread or NSCache?
Use KingFisher download this library and add into your project.
Use code like :
let ProfileUrl = YOUR_URL! as! String
if ProfileUrl.isEmpty == true {
YOURIMAGE_VIEW.image = UIImage.init(named: "ic_default_IMAGE.png")
}else{
let fbUrl = NSURL(string: ProfileUrl )!
YOURIMAGE_VIEW.kf_setImageWithURL(fbUrl, placeholderImage: nil,
optionsInfo: [.Transition(ImageTransition.Fade(1))],
progressBlock: { receivedSize, totalSize in
},
completionHandler: { image, error, cacheType, imageURL in
print("Finished")
})
}
Retrive image from cache file
KingfisherManager.sharedManager.retrieveImageWithURL(url, optionsInfo: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, imageURL) -> () in
print(image)
})
Using Swift 3 :-
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BrandImagesCell", for: indexPath) as! BrandImagesCell
//let StrUrl = NSURL(string: self.arrImages[indexPath.row])! as URL
let urlPath: String = self.arrImages[indexPath.row]
//let StrUrl: NSURL = NSURL(string: urlPath)!
if 0 != arrImages.count
{
let imgUrl = urlPath
//Add Default image
if imgUrl.isEmpty == true {
cell.brandImage.image = UIImage.init(named: "placeholder.png")
}
else
{
let url = URL(string: imgUrl)!
cell.brandImage.kf.setImage(with: url,
placeholder: nil,
options: [.transition(.fade(0.5))],
progressBlock: { receivedSize, totalSize in
print("\(indexPath.row + 1): \(receivedSize)/\(totalSize)")
},
completionHandler: { image, error, cacheType, imageURL in
print("Finished")
//print("\(indexPath.row + 1): Finished")
})
}
}
return cell
}
I want to use UICollectionView for displaying the images and I am getting that images by api calling.
Question: so I am getting images path via api calling so how can I display it to UICollectionView??
here is my code ::
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
cell.imagev.image = dic["image"] as? UIImage
return cell
}
and here is my api response
(
{
image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/esquire.jpg";
slug = esquire;
},
{
image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/forbes.jpg";
slug = forbes;
},
{
image = "http://radio.spainmedia.es/wp-content/uploads/2015/12/tapas.jpg";
slug = tapas;
}
)
so how can I display this images in my UICollectionView
UPDATE:: While using commented code getting strange issue i am calling my webservice in viewdidload
override func viewDidLoad() {
super.viewDidLoad()
webimages()
// Do any additional setup after loading the view, typically from a nib.
}
and its started to call webservice
func webimages()
{
let url = "http://radio.spainmedia.es/podcasts/"
request(.GET, url, parameters: nil, encoding: .JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in
print(response.result.value)
self.imagearray = (response.result.value) as! NSMutableArray
print(self.imagearray)
}
}
but after requesting its suddenly go to cellForItemAtIndexPath so my "imagearray" found nil there. and then its comeback to webimages() and giving me api response.
So how can I solve this?
we have array of string we are passing single string here so can you please tell me that what is the solution
We have array of string we are passing single string here so can you please tell me that what is the solution
enter image description here
You are setting a URL string as UIImage. You first have to retrieve image from that URL first. Use the following method for quick remedy:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
if imagearray.count > 0
{
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let imgURL: NSString = dic!["image"] as! NSString //Get URL string
let url = NSURL.URLWithString(imgURL); //Create URL
var err: NSError?
var imageData :NSData = NSData(contentsOfURL: url, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)! //Fetch Image Data
var cellImage = UIImage(data:imageData) //Create UIImage from Image data
cell.imagev.image = cellImage //Set image
}
return cell
}
Notice that this is fetching content of image URL in a synchronous call so that would freeze your UI until download completes. Also this is not caching the Image so images will be downloaded over and over again when you scroll and cells are recreated. To avoid that I'd suggest caching .
For better results, This is how you load image asynchronously, without freezing the UI and cache the images to avoid network load.
You first have to create a class first like this:
class ImageLoader {
var cache = NSCache() //Create cache
class var sharedLoader : ImageLoader {
struct Static {
static let instance : ImageLoader = ImageLoader()
}
return Static.instance
}
func imageForUrl(urlString: String , indexPathArg:NSIndexPath!, completionHandler:(image: UIImage?, url: String,indexPathResponse:NSIndexPath?) -> ()) {
let currentIndexPath: NSIndexPath! = indexPathArg.mutableCopy() as! NSIndexPath
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in
let data: NSData? = self.cache.objectForKey(urlString) as? NSData
//Check if image data for this URL already exists in Cache
if let goodData = data {
//data exists, no need to download it again. Just send it
let image = UIImage(data: goodData)
dispatch_async(dispatch_get_main_queue(), {() in
completionHandler(image: image, url: urlString,indexPathResponse: currentIndexPath)
})
return
}
//Data does not exist, We have to download it
let downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!,completionHandler: { (data: NSData?, response:NSURLResponse?, error: NSError?) -> Void in
if (error != nil) {
//Download failed
completionHandler(image: nil, url: urlString, indexPathResponse: currentIndexPath)
return
}
if data != nil {
//Download successful,Lets save this downloaded data to our Cache and send it forward as UIImage
let image = UIImage(data: data!)
self.cache.setObject(data!, forKey: urlString)
dispatch_async(dispatch_get_main_queue(), {() in
completionHandler(image: image, url: urlString, indexPathResponse: currentIndexPath)
})
return
}
})
downloadTask.resume()
})
}
}
Then you have to modify your collectionview delegate like this:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
if imagearray.count > 0
{
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let imgURL: NSString = dic!["image"] as! NSString//Get URL string
ImageLoader.sharedLoader.imageForUrl(imgURL as String,indexPathArg: indexPath, completionHandler:{(image: UIImage?, url: String, indexPathResponse: NSIndexPath?) in
let indexArr:NSArray = collectionView!.indexPathsForVisibleItems()
if indexArr.containsObject(indexPathResponse!)
{
cell.imagev.image = image //Set image
}
})
}
return cell
}
Now it will load your image asynchronously and will download it only if necessary. Great Success! (To quote Borat). I have added comments so that you can understand What's going on in my code and Daniel's code :)
To Fix your crash issue which is not a part of your original question and instead a different problem you created, Return count of items in section to be count of your image array and reload collectionview once you have retrieved your data:
func webimages()
{
let url = "http://radio.spainmedia.es/podcasts/"
request(.GET, url, parameters: nil, encoding: .JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in
print(response.result.value)
self.imagearray = (response.result.value) as! NSMutableArray
print(self.imagearray)
//Reload Collection view
self.collectionView?.reloadData()
}
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imagearray.count
}
Credits for Imageloader class: Daniel Sattler
Special Thanks to: CouchDeveloper
Pretty easy you got to downlaod the image from that url and set it as the image for the image view,
Try this, https://github.com/natelyman/SwiftImageLoader
Add the ImageLoader class to your project and modify the collectionview data source as below,
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let dic = imagearray .objectAtIndex(indexPath.row) as! NSDictionary
let cell :imagecell = collectionView.dequeueReusableCellWithReuseIdentifier("imagecell", forIndexPath: indexPath) as! imagecell
//cell.imagev.image = dic["image"] as? UIImage
ImageLoader.sharedLoader.imageForUrl(dic["image"], completionHandler: {(image: UIImage?, url: String) in
cell.imagev.image = image
})
return cell
}
This is an asynchronous image loading class so UI would not freeze or give you any other problems if you are against using any third party libs or classes please do it manually as #NSNoob 's answer.
Other good image loading libraries are,
https://github.com/nicklockwood/AsyncImageView
https://github.com/onevcat/Kingfisher
https://github.com/MengTo/Spring/blob/master/Spring/AsyncImageView.swift
https://github.com/anas10/AsyncImageView-Swift
You can extend UIImageView as following -
extension UIImageView {
public func imageFromU(urlString: String) {
if let url = NSURL(string: urlString) {
let request = NSURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in
if let imageData = data as NSData? {
self.image = UIImage(data: imageData)
}
}
}
}
}
Then in any UIImageView you will have a very simple helper method as follows -
yourImageView.imageFromURL("https://yoururl.com/image.png")
And in your case
cell.imagev.image.imageFromURL(dic["image"])
if let url = NSURL(string: "http://www.apple.com/euro/ios/ios8/a/generic/images/og.png") {
if let data = NSData(contentsOfURL: url){
imageURL!.contentMode = UIViewContentMode.ScaleAspectFit
imageURL!.image = UIImage(data: data)
}
}
The app can create a custom album in the standard iOS photos application, but I have been unable to find a way for the app to gather all the images from that album to be displayed within the app.
Currently, the app is able to gather images from all the albums, just not one is particular.
let resultCollections = PHAssetCollection.fetchAssetCollectionsWithType(
.Album,
subtype: .AlbumRegular,
options: nil)
resultCollections.enumerateObjectsUsingBlock({
(object, index, stop) -> Void in
let collection = object as! PHAssetCollection
let result = PHAsset.fetchAssetsInAssetCollection(collection, options: nil)
result.enumerateObjectsUsingBlock({
(object, index, stop) -> Void in
let asset = object as! PHAsset
self.images.append(asset)
})
})
I have seen other questions that might be marked as duplicates, however the majority of them are talking about opening a UIPickerView to a custom album. This is a possible duplicate of How to fetch all images from custom Photo Album - swift however, it was never answered.
So, how can an iOS app gather all images from a particular photos album?
Add fetchOptions like below
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", YourAlbumTitle)
let resultCollections = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .AlbumRegular, options: fetchOptions)
Actually, the album title isn't a unique value, they can be duplicated. so I recommend using localIdentifier like below if your app access multiple albums.
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "localIdentifier = %#", YourAlbumLocalIdentifier)
let resultCollections = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .AlbumRegular, options: fetchOptions)
Working Code For Swift 4
My Answer might help you and others(https://stackoverflow.com/a/35178022/4795651) but then also adding the code here..!!
import Photos
func fetchCustomAlbumPhotos()
{
let albumName = "Album Name Here"
var assetCollection = PHAssetCollection()
var albumFound = Bool()
var photoAssets = PHFetchResult<AnyObject>()
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", albumName)
let collection:PHFetchResult = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: fetchOptions)
if let firstObject = collection.firstObject{
//found the album
assetCollection = firstObject
albumFound = true
}
else { albumFound = false }
_ = collection.count
photoAssets = PHAsset.fetchAssets(in: assetCollection, options: nil) as! PHFetchResult<AnyObject>
let imageManager = PHCachingImageManager()
photoAssets.enumerateObjects{(object: AnyObject!,
count: Int,
stop: UnsafeMutablePointer<ObjCBool>) in
if object is PHAsset{
let asset = object as! PHAsset
print("Inside If object is PHAsset, This is number 1")
let imageSize = CGSize(width: asset.pixelWidth,
height: asset.pixelHeight)
/* For faster performance, and maybe degraded image */
let options = PHImageRequestOptions()
options.deliveryMode = .fastFormat
options.isSynchronous = true
imageManager.requestImage(for: asset,
targetSize: imageSize,
contentMode: .aspectFill,
options: options,
resultHandler: {
(image, info) -> Void in
self.photo = image!
/* The image is now available to us */
self.addImgToArray(uploadImage: self.photo!)
print("enum for image, This is number 2")
})
}
}
}
func addImgToArray(uploadImage:UIImage)
{
self.images.append(uploadImage)
}
For Swift 2.1
import Photos
func FetchCustomAlbumPhotos()
{
var albumName = "SwiftAlbum"
var assetCollection = PHAssetCollection()
var albumFound = Bool()
var photoAssets = PHFetchResult()
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "title = %#", albumName)
let collection:PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .Any, options: fetchOptions)
if let first_Obj:AnyObject = collection.firstObject{
//found the album
assetCollection = collection.firstObject as! PHAssetCollection
albumFound = true
}
else { albumFound = false }
var i = collection.count
photoAssets = PHAsset.fetchAssetsInAssetCollection(assetCollection, options: nil)
let imageManager = PHCachingImageManager()
// let imageManager = PHImageManager.defaultManager()
photoAssets.enumerateObjectsUsingBlock{(object: AnyObject!,
count: Int,
stop: UnsafeMutablePointer<ObjCBool>) in
if object is PHAsset{
let asset = object as! PHAsset
print("Inside If object is PHAsset, This is number 1")
let imageSize = CGSize(width: asset.pixelWidth,
height: asset.pixelHeight)
/* For faster performance, and maybe degraded image */
let options = PHImageRequestOptions()
options.deliveryMode = .FastFormat
options.synchronous = true
imageManager.requestImageForAsset(asset,
targetSize: imageSize,
contentMode: .AspectFill,
options: options,
resultHandler: {
(image, info) -> Void in
self.photo = image!
/* The image is now available to us */
self.addImgToArray(self.photo)
print("enum for image, This is number 2")
})
}
}
}
func addImgToArray(uploadImage:UIImage)
{
self.images.append(uploadImage)
}
class AlbumModel {
let name:String
let count:Int
let asset:NSMutableArray
init(name:String, count:Int, asset:NSMutableArray) {
self.name = name
self.count = count
self.asset = asset
}
}
class yourCustomCell: UITableViewCell {
//MARK:- Properties
#IBOutlet weak var collectionView: UICollectionView!
//MARK:- initialization methods
override func awakeFromNib() {
super.awakeFromNib()
// setupView()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
//MARK:- Setup collectionView datasource and delegate
func setCollectionViewDataSourceDelegate<T:UICollectionViewDataSource & UICollectionViewDelegate>(dataSourceDelegate: T, forRow row: Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row
collectionView.reloadData()
}
}
class ViewController: UIViewController {
var tablearray = NSMutableArray()
func getAssetThumbnail(asset: PHAsset) -> UIImage {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var thumbnail = UIImage()
option.isSynchronous = true
manager.requestImage(for: asset, targetSize: CGSize(width: 100, height: 100), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
thumbnail = result!
})
return thumbnail
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//print(UnladenSwallow.unknown)
let fetchOptions = PHFetchOptions()
let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .any, options: fetchOptions)
let topLevelfetchOptions = PHFetchOptions()
let topLevelUserCollections = PHCollectionList.fetchTopLevelUserCollections(with: topLevelfetchOptions)
let allAlbums = [topLevelUserCollections, smartAlbums]
var name = ""
smartAlbums.enumerateObjects({
if let collection = $0.0 as? PHAssetCollection{
name = collection.localizedTitle!
let image_arry = NSMutableArray()
let result = PHAsset.fetchAssets(in: collection, options: nil)
result.enumerateObjects({ (object, index, stop) -> Void in
let asset = object
image_arry.add(self.getAssetThumbnail(asset: asset))
})
let newAlbum = AlbumModel(name: name, count: collection.estimatedAssetCount, asset:image_arry)
self.tablearray.add(newAlbum)
}
})
topLevelUserCollections.enumerateObjects({
if let collection = $0.0 as? PHAssetCollection{
name = collection.localizedTitle!
let image_arry = NSMutableArray()
let result = PHAsset.fetchAssets(in: collection, options: nil)
result.enumerateObjects({ (object, index, stop) -> Void in
let asset = object
image_arry.add(self.getAssetThumbnail(asset: asset))
})
let newAlbum = AlbumModel(name: name, count: collection.estimatedAssetCount, asset:image_arry)
self.tablearray.add(newAlbum)
}
})
print(self.tablearray)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController: UITableViewDataSource,UITableViewDelegate{
func numberOfSections(in tableView: UITableView) -> Int{
return self.tablearray.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
let album = self.tablearray[section] as! AlbumModel
return album.name
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! yourCustomCell
cell.setCollectionViewDataSourceDelegate(dataSourceDelegate: self, forRow: indexPath.section)
return cell
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let album = self.tablearray[collectionView.tag] as! AlbumModel
print("count = \(album.asset.count)")
return album.asset.count;
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let album = self.tablearray[collectionView.tag] as! AlbumModel
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "col", for: indexPath)
let img = cell.viewWithTag(111) as! UIImageView
img.image = album.asset.object(at: indexPath.row) as? UIImage
return cell
}
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: IndexPath) {
print("get selected collectionview itemindex \(indexPath.row)")
}