Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect user interactions on a whole viewcontroller

Tags:

ios

swift

swift3

I would like to detect the user interactions on a UIViewController like

  1. Editing Text Fields
  2. Selecting picture from gallery
  3. Picker view selections

Its indented to show a notification like "You may lose data you have entered" when user goes out of page. Can be back button.

Have seen many answers but i need the best and proper way of doing this functionality.

like image 606
Saranjith Avatar asked Sep 26 '17 14:09

Saranjith


People also ask

How do I know if ViewController is visible?

The view's window property is non-nil if a view is currently visible, so check the main view in the view controller: Invoking the view method causes the view to load (if it is not loaded) which is unnecessary and may be undesirable. It would be better to check first to see if it is already loaded.

How do I connect storyboard to ViewController?

Create a new IBOutlet called shakeButton for your storyboard button in your ViewController. swift file. Select the shake button in Interface Builder. Then hold down the control button ( ⌃ ) and click-drag from the storyboard button into your ViewController.

How to add view controller in Xcode?

To create a new view controller, select File->New->File and select a Cocoa Touch Class. Choose whether to create it with Swift or Objective-C and inherit from UIViewController . Don't create it with a xib (a separate Interface Builder file), as you will most likely add it to an existing storyboard.


3 Answers

my two cents.

  • what are you asking is to implement a NON-iOS behaviour, see for example iOS prefs: is very rare to ask user to be careful or his data will be lost.

  • the iOS logic is usually:

    a) automatically save every data (to help user..) and save it

    b) collect data as user moves, and eventually at the end save or throw it away

    c) iOS user has in his "DNA" this kind of behaviour, so is weird to ask to save... it seems windows-style use of UI.

    d) as a programmer what You want to implement is a bit lengthy, as You are not follow Apple HIG, so there is no specific call to get it. What other guys are saying is generally correct, you have to map multiple callbacks/delegates.

like image 194
ingconti Avatar answered Oct 08 '22 21:10

ingconti


That main problem is - user could make changes but become same object. Means change 10500 times filed and select same that was on start. Is Recent Updated ? I guess no !.

How to get diff ? - Compare a hash ! How to do that ? - use "==". That all.

A bit of abstract code.

  1. Override back button. (Yeah, its bad practice but there is not documented way to own back button process)

  2. Make a diff

  3. Show alert

struct CustomModel : Hashable, Equatable {
        var name : String
        //your custom model

    public var hashValue: Int {
        return name.hashValue
    }

    static func ==(lhs: CustomModel, rhs: CustomModel) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }
}

class VoteViewController : UIViewController {
    private var originalModel : CustomModel!
    private var mutableCopy : CustomModel!

    override func viewDidLoad() {
        super.viewDidLoad()
        mutableCopy = originalModel
        navigationItem.hidesBackButton = true
        let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: self, action: #selector(VoteViewController.back(sender:)))
        navigationItem.leftBarButtonItem = newBackButton
    }

    func back(sender: UIBarButtonItem) {
        // ChechDataModification
        guard mutableCopy == originalModel else {
            presentAlertPop()
            return
        }

        _ = navigationController?.popViewController(animated: true)
    }

    func presentAlertPop(){
        //You may lose data you have entered !
    }
}
like image 2
Max Vitruk Avatar answered Oct 08 '22 21:10

Max Vitruk


The best way to use in Swift is to take the advantage of swift property observer. Let's assume you have user profile view with:

  • First, last and middle name field to enter
  • Image view to select and show user picture
  • A date of birth field to select dates from picker view

Your model will look this:

struct ProfileModel {
    var isUpdated: Bool = false
    var firstName: String {
        willSet {
            if newValue != firstName {
                isRecentUpdated = true
            }
        }
    }
    var middleName: String {
        willSet {
            if newValue != middleName {
                isRecentUpdated = true
            }
        }
    }
    var lastName: String {
        willSet {
            if newValue != lastName {
                isRecentUpdated = true
            }
        }
    }
    var profilePhoto: URL {
        willSet {
            if newValue != profilePhoto {
                isRecentUpdated = true
            }
        }
    }
    var dob: Date {
        willSet {
            if newValue != dob {
                isRecentUpdated = true
            }
        }
    }
}

Here, model has state variable isUpdated which track model state change whenever any of property modified to new value - have kept check if indeed user action has changed existing value in model.

Whenever, you launch profile screen you can set isUpdated to false so that you can track updated profile data on each launch of profile view.

OR

If you are populating this model from server then after every fetch you can reset the model state (isUpdated flag) which then can track any further change.

Hope it helps.

like image 2
manismku Avatar answered Oct 08 '22 22:10

manismku