My swifts code goal is to place a image in the imageview pic in class customtv when the user imports a photo from the photo gallery. The code works if you hit the import button twice but on the first time the code does not work and nothing happens you can see me testing the code in the gif below. I tried to start the index at 1 but that is not working. I think imagePickerController is what is causing the problem.
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
var selectedIndexPath = IndexPath(row: 0, section: 0)
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 118
}
@objc func importPhoto(_ button: UIButton) {
selectedIndexPath = IndexPath(row: button.tag , section: 0)
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let selectedImage = info[.originalImage] as? UIImage else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
guard let cell = tableview.cellForRow(at: selectedIndexPath) as? customtv else { return }
cell.pic.image = selectedImage
tableview.reloadRows(at: [selectedIndexPath], with: .automatic)
dismiss(animated: true, completion: nil)
}
@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
// we got back an error!
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
} else {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
var tableview = UITableView()
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! customtv
cell.btn.tag = indexPath.row
cell.btn.addTarget(self, action: #selector(importPhoto), for: .touchDown)
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableview.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
view.addSubview(tableview)
tableview.register(customtv.self, forCellReuseIdentifier: "cell")
tableview.delegate = self
tableview.dataSource = self
}
}
class customtv: UITableViewCell {
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
print(self.frame.width)
return view
}()
override func layoutSubviews() {
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
}
lazy var btn : UIButton = {
let press = UIButton(frame: CGRect(x: 180, y: 40, width: 120 , height: 50))
press.backgroundColor = .blue
press.setTitle("Import", for: .normal)
return press
}()
lazy var pic : UIImageView = {
let press = UIImageView(frame: CGRect(x: 20, y: 40, width: 120 , height: 50))
press.backgroundColor = .red
return press
}()
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(animated, animated: true)
addSubview(backView)
backView.addSubview(pic)
backView.addSubview(btn)
}
}
You are using the table view in a wrong manner. The table view is using the UITableViewDataSource methods to retrieve the data by calling
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
. In that function - and only there - you fill the cell with the appropriate data. When you set the image inimagePickerController(_:, didFinishPickingMediaWithInfo:)
, what happens is that the next time the user scrolls or the table view decides that it needs to re-display the cell, it callscellForRowAt
which then will reset the image that you just set.Therefore, you need to keep references to the images that the user selects in a property
Instead of storing the (binary image) data in
selectedImages
, you could also just store a reference to the camera roll. See Storing a reference to a camera roll image - Swift 4 for details