Change image of custom cell with UIImagePickerController - swift

I’ve created a custom cell that has imageView inside. I want to change the image of that imageView with the help of UIImagePickerController. When I check this function in the simulator, it doesn’t change anything. Can’t figure out the problem.
The property of the custom cell:
let imageOfPlace: UIImageView = {
let iv = UIImageView()
return iv
}()
The cell in tableView:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: ImageOfPlaceViewCell.identifierOfImageOfPlaceCell) as! ImageOfPlaceViewCell
Functions of picker:
func chooseImagePickerController(source: UIImagePickerController.SourceType) {
if UIImagePickerController.isSourceTypeAvailable(source) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
imagePicker.sourceType = source
present(imagePicker, animated: true)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let myCell = ImageOfPlaceViewCell()
myCell.imageOfPlace.image = info[.editedImage] as! UIImage
picker.dismiss(animated: true)
}

You're creating a new cell here:
let myCell = ImageOfPlaceViewCell()
Instead of that you need to change image of an existing cell. You need to get an existing cell object from the table. To do this you can use tableView.cellForRow, and pass there index path of your row.
I'm not sure about your table structure, but you also need to make sure that when you reload your table it won't disappear, so you can store picked image somewhere else to use next time in cellForRowAt.
var pickedImage: UIImage?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: ImageOfPlaceViewCell.identifierOfImageOfPlaceCell) as! ImageOfPlaceViewCell
cell.imageOfPlace.image = pickedImage
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
let image = info[.editedImage] as! UIImage
pickedImage = image
let myCell = tableView.cellForRow(at: IndexPath(row: 0, section: 0))
myCell?.imageOfPlace.image = info[.editedImage] as! UIImage
picker.dismiss(animated: true)
}
p.s. Also I'm not sure what's this let cell = tableView.dequeueReusableCell(withIdentifier: "cell")! before your if, it's probably redundant(at least in case when you return cell from that if)

Related

Loading an Image file from Firebase Storage using SDWebImage

I am trying to load an image from my Firebase Storage to be displayed on my app view.
I have 2 classes mainly
Main "ClassView" that includes a tableView.
A custom tableViewCell - "ClassCell" (This class includes an imageView where I want to display the picture from firestore. - imageView is called classImage.
Below is the tableView Data Source Extension.
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
tableView.register(UINib(nibName: K.tableCellNibName, bundle: nil), forCellReuseIdentifier: K.tableCellIdentifier)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let storageRef = storage.reference()
let reference = storageRef.child(K.FStore.classImagesPath)
let placeholderImage = UIImage(named: "placeholder.png")
let imageView: UIImageView = self.imageView
let cell = tableView.dequeueReusableCell(withIdentifier: K.tableCellIdentifier, for: indexPath) as! ClassCell
//below is where I try to set the my image but it is not changing anything
cell.classImage?.sd_setImage(with: reference, placeholderImage: placeholderImage)
//This I tried to make sure that I am can access the image right and it worked just fine
// cell.classImage?.backgroundColor = .black
return cell
}
The Image is not displayed using the sd_setImage method. Any help would be highly appreciated if I have any error in my code or missing a declaration anywhere.
Below is what I am getting when I run the simulator. Instead of the image displayed in these black boxes, they are empty. Also, the imageView.image is returning nil so most probably the sd_setImage is not placing the image right.
self.imgSidebarMenuImage.sd_imageIndicator = SDWebImageActivityIndicator.whiteLarge
self.imgSidebarMenuImage.sd_setImage(with: URL(string: (person["image"] as! String)), placeholderImage: UIImage(named: "logo"))
try this
#1
let storage = Storage.storage().reference(withPath: “YOUR_PATH”)
storage.downloadURL { (url, error) in
if error != nil {
print((error?.localizedDescription)!)
return
}
print(“Download success”)
//url = your will get an image URL
self.someImageURL = url!
}
#2
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// cell identifier methods
var item = itemData[indexPath.row]
let referenceImage: StorageReference = storageRef.child("YOUR_PATH")
let url = URL(string: referenceImage!)!
cell.itemImage?.sd_setImage(with: url, placeholderImage: #imageLiteral(resourceName: "placeholder"))
}
}
return cell
}

How to save an image from collection view to document directory and then retrieve it in the same cell in Swift 3.0?

I am creating an application where users upload images to a collection view cell by tapping on the image. I am able to post the image to the desired cell, but when the app closes it disappears.
I have made the app save one image, but I am having trouble assigning the images to their own cells. As such, I get situations where all the cells are the last uploaded image.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "reuse_cell", for: indexPath) as! CollectionViewCell
self.currentCellBeingEdited = self.collectionView.cellForItem(at: indexPath) as! CollectionViewCell?
cell.backgroundColor = IMColors.flatGrey
let defaults = UserDefaults.standard
var imageData = defaults.data(forKey: "name")
if let imageData = imageData {
let thumbnailImage = UIImage(data: imageData)
cell.image.image = thumbnailImage
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.currentCellBeingEdited = self.collectionView.cellForItem(at: indexPath) as! CollectionViewCell?
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
print(indexPath.row)
present(imagePicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
imagePicker.dismiss(animated: true, completion: nil)
let pickedImage = info[UIImagePickerControllerEditedImage] as? UIImage
self.currentCellBeingEdited?.image.image = pickedImage
self.currentCellBeingEdited = nil
let dataForImage = pickedImage
let data: NSData = UIImageJPEGRepresentation(dataForImage!, 1.0)! as NSData
let defaults = UserDefaults.standard
var imageForCell = String(describing: currentCellBeingEdited)
defaults.set(data, forKey: "name")
}

Prototype cell + image + delegate

So this is what happened: I created a tableView and delegated some stuff to it from another controller. The textLabels from the cells are working fine, but whenever I add cell.imageView?.image, all cells change to that specific image.
Any ideas on how to fix it? The textLabels are static but the images are not.
Here I receive the image to the tableView:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell!
let row = indexPath.row
let titulo = arrayInfo[row]
let image = imgR
cell.textLabel!.text = titulo
cell.imageView?.image = image
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "add") {
let view = segue.destinationViewController as! EsseVaiPassar
view.delegate = self
view.delegateimg = self
}
}
and here I pass it from the controller to the other one with the tableView:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
imagemRecebida.contentMode = .ScaleAspectFit
imagemRecebida.image = pickedImage
delegateimg?.passImage(pickedImage!)
print("IMAGE PICKED: \(pickedImage)")
dismissViewControllerAnimated(true, completion: nil)
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
The code is working as intended. For your textview, you are asking the value arrayInfo[row]. So for each cell as the indexPath.row changes the respective element from the array is displayed in the text field.
But for your image, it is just a single image and not an array. You aren't using indexPath.row to select a particular image.
To add different images to your tableView, just create an array of image like you have created an array of String. Just implement the logic you have implemented for the textView cell.imageView?.image = image[indexPath.row]
To add image only to the first cell and leave the remaining cells blank use this
if indexPath.row == 0
{
cell.imageView?.image = image
}
In `cellForRowAtIndexPath' you have this code:
...
let image = imgR
cell.textLabel!.text = titulo
cell.imageView?.image = image
...
You are assigning imgR to the image constant, then you are assigning image to imageView?.image, so every cell will get the image stored in the variable imgR.
If you have multiple images, you need to put logic to pull the correct image for the correct row (usually an array of items).

Taking a snapshot of a UICollectionViewCell

I am making a tvOS app and I want it to look similarly to the Movies app. Therefore I have a UICollectionView. Now my cells are not just simple UIImageViews, but are rather somewhat more complicated.
I still want to have the nice focus visual effect (making the cell image bigger and having the light effect on it when the user swipes the remote). So what I am trying to do is render my cell, then take a snapshot of it and then show this snapshot instead of the cell itself. This is how I do it:
extension UIView {
var snapshot : UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, true, 0.0)
drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
...
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = NSBundle.mainBundle().loadNibNamed("ContentCell", owner: self, options: nil)[0] as! ContentCell
cell.update()
let cellSnapshot = cell.snapshot
let snapshotCell = collectionView.dequeueReusableCellWithReuseIdentifier("SnapshotCell", forIndexPath: indexPath) as! SnapshotCell
snapshotCell.snapshotImageView.image = cellSnapshot
return snapshotCell
}
However, all this does is show a black cell. Any ideas what might I be doing wrong?
You should look here
In Swift it will be smth like that:
extension UIView {
var snapshot : UIImage? {
var image: UIImage? = nil
UIGraphicsBeginImageContext(bounds.size)
if let context = UIGraphicsGetCurrentContext() {
self.layer.renderInContext(context)
image = UIGraphicsGetImageFromCurrentImageContext()
}
UIGraphicsEndImageContext()
return image
}
}

UICollectionView image flickering

I have a UICollectionView that shows cells at fullscreen (i.e. a gallery).
Sometimes, when swiping for the new image, an image other than the right one is displayed for less than a second, than the image is updated.
Other times, the wrong image is shown, but if you swipe left and than right (i.e. the image disappear and reappear) than the right image comes up.
I don't understand the cause of this behavior.
Images are downloaded asynchronously when the collection view needs them.
Here is the code:
let blank = UIImage(named: "blank.png")
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! UICollectionViewCell
let image = images[indexPath.row]
if let imageView = cell.viewWithTag(5) as? UIImageView {
imageView.image = blank
if let cachedImage = cache.objectForKey(image.url) as? UIImage {
imageView.image = cachedImage
} else {
UIImage.asyncDownloadImageWithUrl(image.url, completionBlock: { (succeded, dimage) -> Void in
if succeded {
self.cache.setObject(dimage!, forKey: image.url)
imageView.image = dimage
}
})
}
}
return cell
}
where UIImage.asyncDownloadImageWithUrl is:
extension UIImage {
static func asyncDownloadImageWithUrl(url: NSURL, completionBlock: (succeeded: Bool, image: UIImage?) -> Void) {
let request = NSMutableURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response, data, error) in
if error == nil {
if let image = UIImage(data: data) {
completionBlock(succeeded: true, image: image)
}
} else {
completionBlock(succeeded: false, image: nil)
}
})
}
}
and for the first image shown:
func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
if let index = self.index {
let newIndexPath = NSIndexPath(forItem: index, inSection: 0)
self.collectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
self.index = nil
}
}
This is what i think it's happening:
Cell A appears
Request for image A is made to load on Cell A
Cell A disappears from screen
Cell A reappears (is reused)
Request for image B is made to load on Cell A
Request for image A is complete
Image A loads on to the Cell A
Request for image B is complete
Image B loads on to the Cell A
This is happening because you are not keeping track of which image url should load on the completion block.
Try this:
One way to do that is to store the url of the image that should be there in your UICollectionViewCell. To do that, create a subclass:
class CustomCollectionViewCell:UICollectionViewCell {
var urlString = ""
}
Then:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CustomCollectionViewCell
let image = images[indexPath.row]
if let imageView = cell.viewWithTag(5) as? UIImageView {
imageView.image = blank
cell.urlString = image.url.absoluteString
if let cachedImage = cache.objectForKey(image.url) as? UIImage {
imageView.image = cachedImage
} else {
UIImage.asyncDownloadImageWithUrl(image.url, completionBlock: { (succeded, dimage) -> Void in
if succeded {
self.cache.setObject(dimage!, forKey: image.url)
//
// This can happen after the cell has dissapeared and reused!
// check that the image.url matches what is supposed to be in the cell at that time !!!
//
if cell.urlString == image.url.absoluteString {
imageView.image = dimage
}
}
})
}
}
return cell
}
For a more accurate reply, post the project (or a barebones version of it). It's a lot of work to reproduce your setup and test.