i want my swift code to use delegate to import a photo from photo gallery to a specific table view cell. What is going on right now is the photo is being imported to always to go the first cell. So if the user clicks the import button from the second cell the photo should go to the second cell. The tag is not working. I want to use delegation if possible.
import UIKit
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,CustomTvCellDelegateadd, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
@objc func addCeller(_ customTV: CustomTv, location: CGPoint) {
selectedIndexPath = IndexPath(row: 0, section: 0)
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
var cellCount = 5
var tableview = UITableView()
var selectedIndexPath = IndexPath(row: 0, section: 0)
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.reloadData()
dismiss(animated: true, completion: nil)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellCount // use a variable here so you can change it as you delete cells, else it will crash
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 118
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTv
cell.addd.tag = indexPath.row
cell.delegatef = self
cell.addd.addTarget(self, action: #selector(addCeller), for: .touchDown)
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
tableview.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height * 0.8)
view.addSubview(tableview)
tableview.register(CustomTv.self, forCellReuseIdentifier: "cell")
tableview.delegate = self
tableview.dataSource = self
}
}
// you need to declare a cell delegate that will let your tableview know when the button was tapped on the cell
protocol CustomTvCellDelegateadd: AnyObject {
func addCeller(_ customTV: CustomTv, location: CGPoint)
}
class CustomTv: UITableViewCell { // it's good form to Pascal case your class name ;)
weak var delegatef: CustomTvCellDelegateadd?
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
return view
}()
lazy var addd : UIButton = {
let btn = UIButton(frame: CGRect(x: 250-25, y: 0, width: 100 , height: 55))
btn.backgroundColor = .brown
btn.setTitle("Add", for: .normal)
btn.titleLabel?.textAlignment = .center
return btn
}()
lazy var pic : UIImageView = {
let btn = UIImageView(frame: CGRect(x: 50-25, y: 6, width: 100 , height: 110))
btn.backgroundColor = .systemPink
return btn
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
// moved these calls here instead of on setSelected(_selected:animated:)
addSubview(backView)
backView.addSubview(addd)
backView.addSubview(pic)
}
}
Issue:
selectedIndexPath = IndexPath(row: 0, section: 0)
Hardcoded indexPath value in addCeller
method
Solution:
You need a bit of restructuring of code.
1. capture the button selector in the cell itself, so you can return / pass self as an argument to protocol method. This isnt a very ideal solution (as you are only interested in index path and not the cell itself, but I am not very clear on your idea behind returning CustomTv
as arguement in your protocol method, so am just keeping changes in sync with that decision)
class CustomTv: UITableViewCell { // it's good form to Pascal case your class name ;)
weak var delegatef: CustomTvCellDelegateadd?
lazy var backView : UIView = {
let view = UIView(frame: CGRect(x: 10, y: 6, width: self.frame.width , height: 110))
view.backgroundColor = .green
return view
}()
lazy var addd : UIButton = {
let btn = UIButton(frame: CGRect(x: 250-25, y: 0, width: 100 , height: 55))
btn.backgroundColor = .brown
btn.setTitle("Add", for: .normal)
btn.titleLabel?.textAlignment = .center
btn.addTarget(self, action: #selector(addButtonTapped), for: .touchUpInside)
return btn
}()
lazy var pic : UIImageView = {
let btn = UIImageView(frame: CGRect(x: 50-25, y: 6, width: 100 , height: 110))
btn.backgroundColor = .systemPink
return btn
}()
override func layoutSubviews() {
backView.clipsToBounds = true
backView.frame = CGRect(x: 0, y: 6, width: bounds.maxX , height: 110)
// moved these calls here instead of on setSelected(_selected:animated:)
addSubview(backView)
backView.addSubview(addd)
backView.addSubview(pic)
}
@objc func addButtonTapped() {
self.delegatef?.addCeller(self)
}
}
2. Now that you have CustomTv
instance as a part of your method invocation, get indexpath directly by asking tableView
func addCeller(_ customTV: CustomTv) {
if let indexPath = self.tableview.indexPath(for: customTV) {
selectedIndexPath = indexPath
}
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
present(imagePicker, animated: true, completion: nil)
}
3. Now that you have already set button target, remove the statement from cellForRowAtIndexPath
cell.addd.addTarget(self, action: #selector(addCeller), for: .touchDown)
EDIT 1:
As OP mentioned in comments below, these modification is resulting in compilation error, as I had modified the protocol method declaration and did not update it in the answer, hence editing to reflect the same.
protocol CustomTvCellDelegateadd: AnyObject {
func addCeller(_ customTV: CustomTv)
}
As I already explained in comments below, I wasn't sure the purpose of location argument in method (also if it was intended only to communicate the index of cell selected that is no longer needed with this solution) hence I have omitted the argument from declaration which lead to compilation error :)