Cell in many different ViewControllers - swift

I have a cell which I use in many different vc because I have my app divided in different categories but all use the same cell.
Now I have a button which should trigger the event to share it via other apps like whastapp or facebook.
The problem is that depending on in which category you are you have a different view controller which will display the function.
I can make it work with one but not with 10 different vc in just one cell.
I used an extension to get the parentviewController
extension UIView {
var parentViewController: HomeViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.next
if parentResponder is UIViewController {
return parentResponder as! HomeViewController!
}
}
return nil
}
This will obviously only work at the Home vc.
How can I work around this issue?

You can use a protocol to handle your button action in the view controller:
protocol ShareEventDelegate: class {
func didShareButtonSelected()
}
In your custom cell:
class CustomCell: UITableViewCell {
weak var shareDelegate: ShareEventDelegate?
func yourButtonAction() {
shareDelegate.didShareButtonSelected?()
}
}
Then make your ViewControllers conform to the ShareEventDelegate, for example:
extension HomeViewController: ShareEventDelegate {
func didShareButtonSelected() {
// handle your action here
}
}
And in cellForRow:
cell.shareDelegate = self

Related

How to reload specific TableViewController's tableview in a singleton class in swift

I have a AAATableViewController with tableView.
And I have a separate swift singleton file.
In a singleton, I have a function with some logic and in this logic,
I have
DispatchQueue.main.async {
self.tableView.reloadData()
}
but it shows an error because there is no tableview in a singleton class.
How can I reload AAATableViewController's tableview inside singleton using delegate and protocol?
I read some articles with delegate , but they are all between viewcontrollers, and couldn't figure out.
I am making some assumptions about the structure of your code, but I think you're going to want something like this:
protocol ReloadDelegate: AnyObject {
func reloadTable()
}
struct Singleton {
weak var reloadDelegate: ReloadDelegate?
static var shared = Singleton()
func doSomething() {
DispatchQueue.main.async {
self.reloadDelegate?.reloadTable()
}
}
}
class TableViewController: UITableViewController, ReloadDelegate {
override func viewDidLoad() {
super.viewDidLoad()
Singleton.shared.reloadDelegate = self
}
func reloadTable() {
self.tableView.reloadData()
}
}
When you create the TableViewController, you'll need to set the Singleton's reload delegate to the TableViewController. Now the Singleton knows about the TableViewController and can tell it to reload.

How to call a function in another class? [duplicate]

This question already has an answer here:
How to identify the viewController a button has been added onto?
(1 answer)
Closed 3 years ago.
I have a problem in a TableView. This is the class which contains the TableView.
class LogViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
…
func loadLogList() – > [String] {
…
}
The list contains all Logfiles in my Log file directory. In a custom TableViewCell I insert a button which deletes the Logfile. This is the user defined tableViewCell:
class LogTableViewCell: UITableViewCell {
…
#IBAction func deletePressed(_ sender: Any) {
let fileManager = FileManager.default
do {
try fileManager.removeItem(atPath: logURL!.path)
}
catch let error as NSError {
print("Fehler: \(error)")
}
}
After pressing the button the dependent file will be removed. Now I want to refresh this list. But the Button is in the TableViewCell class and the function for refreshing the list is in the TableView class. How can I refresh the tableview and the corresponding array?
You may use Notification Observer pattern for this, but you can access the tableView of the cell with this extension:
extension UITableViewCell {
var tableView: UITableView? {
return (next as? UITableView) ?? (parentViewController as? UITableViewController)?.tableView
}
}
extension UIView {
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.next
if let viewController = parentResponder as? UIViewController {
return viewController
}
}
return nil
}
}
- So now:
you can simply do tableView?.reloadData() inside the cell.

Get ViewController from inherited UIView class

If I have this extension:
extension UIResponder {
var parentViewController: UIViewController? {
return (self.next as? UIViewController) ?? self.next?.parentViewController
}
}
And this one:
extension UIView {
var getParentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.next
if let viewController = parentResponder as? UIViewController {
return viewController
}
}
return nil
}
}
If I have a class like this:
class MyClass: UIView {
init() {
print("\( parentViewController == nil )")
print("\( getParentViewController == nil )")
}
}
Both results are null.
How I can get the implemented ViewController from my UIView without pass it as parameter (directly from the view)?
You can’t get the view’s next responder in its init because it hasn’t been set yet. An appropriate time would be in didMoveToWindow.
Also, in your own answer, you said “…is the easier way to get the uiviewcontroller”, as if an app has only one instance of UIViewController, but every non-trivial app has multiple view controllers.

Swift Delegate setting a label from a custom popUp textfield

I have a custom popup view that has a UIDatePicker. This, when changed, changes the date of the save time. I also want the label on the in the CustomCell to be updated if the date has changed. I have used a delegate protocol to update the table but I cannot get this protocol to transfer the information on save. Can you help? I think I have hooked up all the correct code in the viewController class. I have tried this answer but I cannot set the delegate in the target class and there isn't a segue A Swift example of Custom Views for Data Input (custom in-app keyboard)
protocol DatePopUpViewDelegate: class {
func pastDate(date: String) // date that is chosen in picker
func isPastDateSet(isSet: Bool) // has chosen new date
}
#IBDesignable class DatePopUpView: UIView {
var delegate: DatePopUpViewDelegate?
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "DatePopUp", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
delegate?.isPastDateSet(false)
return view
}
// close popup
#IBAction func closeButtonDatePopUp(sender: AnyObject) {
if dateToSave != openTime {
if let dateToSave = dateToSave {
SaveData.changedSaveTime = dateToSave
delegate?.pastDate(dateToSave)
delegate?.isPastDateSet(true)
}
} else {
SaveData.changedSaveTime = ""
delegate?.isPastDateSet(false)
}
}
class SaveTableViewCell: UITableViewCell, DatePopUpViewDelegate {
var changeDateLabel: Bool = false
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
changeDateLabel = false
datePopUpViewControllert.delegate = self
}
// delegate functions
func pastDate(date: String) {
self.labelDate = date
print("del date \(date)")
}
func isPastDateSet(isSet: Bool) {
self.changeDateLabel = isSet
print("is set by delegate \(isSet)")
}

WKInterfaceTable, Row Controllers and Button actions in Swift

I'm having problems with a fairly basic task while experimenting with Apple Watch development in Swift. I recently received what appeared to be a perfect answer to the problem in Obj C but I can't seem to translate it.
I have one Interface controller that contains a table with multiple rows of the same row controller. Each row contains two buttons. When the button is tapped it's background image changes, but another function needs to be called in the interface controller class, and this function will need to access class-level variables in the interface controller class.
The Table is wired to the interface controller. And the buttons are wired to the row controller class. Here is my simplified Swift code. Thanks for having a look!
/// MY INTERFACE CLASS ///
class MainBoard: WKInterfaceController {
#IBOutlet weak var TileGrid: WKInterfaceTable!
let numRows = 3
let imageNames = ["img1","img2","img3"]
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
initBoard()
}
func initBoard() {
self.TileGrid.setNumberOfRows(self.numRows, withRowType: "Row")
for var i = 0; i < numRows; i++ {
let tmpImageA = UIImage(named: imageNames[0])
let tmpImageB = UIImage(named: imageNames[1])
let rowOfTiles = self.TileGrid.rowControllerAtIndex(i) as Row
rowOfTiles.backImageA = tmpImageA
rowOfTiles.backImageB = tmpImageB
}
}
func doSomething() {
//this function needs to be called whenever a button is pressed
}
}
///////MY ROW CONTROLLER CLASS ////////////////////////
class Row : NSObject {
// At runtime these will be assigned based on the random game board creation
var backImageA = UIImage(named: "default.png")
var backImageB = UIImage(named: "default.png")
#IBOutlet weak var TileA: WKInterfaceButton!
#IBOutlet weak var TileB: WKInterfaceButton!
#IBAction func TapTileA() {
TileA.setBackgroundImage(backImageA)
//NEED TO CALL FUNCTION DO SOMETHING IN INTERFACE CONTROLLER
}
#IBAction func TapTileB() {
TileB.setBackgroundImage(backImageB)
//NEED TO CALL FUNCTION DO SOMETHING IN INTERFACE CONTROLLER
}
}
My best answer would be to create a delegate in your RowController class, then implement this delegate in your InterfaceController
The delegate could have methods buttonOneClickHappened and buttonTwoClickHappened
Then each RowController has the delegate as a property, and when you create the RowControllers call setDelegate: self where self is your InterfaceController
Hope this helps.