简体   繁体   中英

How to count how many times all classes are called

I want the user to be able to know how many times they have visited each class. Then add together the totals from each page together to form a group sum. I want to print the total sum in the log file in each of the two view controllers. So just one string should be printed.

class oneV: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        UserDefaults.standard.set(true, forKey: "VC1")
    }
}

class twoV: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        UserDefaults.standard.set(true, forKey: "VC2")
    }
}

If you mean visited each view controller, when you say visited each class. Then i'd recommend you do it viewDidAppear .

class YourViewController: UIViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        let key = String(describing: type(of: self))
        let count = UserDefaults.standard.value(forKey: key) as? Int ?? 0
        UserDefaults.standard.set(value + 1, forKey: key)
    }

}

To make it simpler, you could use an extension on UIViewController .

extension UIViewController {

    func updateVisitCount() {
        let key = String(describing: type(of: self))
        let count = UserDefaults.standard.value(forKey: key) as? Int ?? 0
        UserDefaults.standard.set(count + 1, forKey: key)
    }

}

Or, if you need this for every view controller that you create, then you can create a base view controller which you would use everywhere instead of UIViewController .

class BaseViewController: UIViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        updateVisitCount()
    }

}

The most automatic solution would be inject the accounting call in viewDidLoad without replacing the original viewDidLoad .

Here demo purpose i've created a sample Playground

import UIKit
import PlaygroundSupport

extension UIViewController {
    @objc dynamic func substitutedViewDidAppear() {
        print("This is injected code in view did appear")
        substitutedViewDidAppear() // it may look like recursive, but it isn't, actually it calls the original `viewDidAppear` method.
    }

    class func swizzle() {
        let originalMethod = class_getInstanceMethod(UIViewController.self, #selector(viewDidAppear(_:)))
        let substitutedMethod = class_getInstanceMethod(UIViewController.self, #selector(substitutedViewDidAppear))

        if  let originalMethod = originalMethod,
            let substitutedMethod = substitutedMethod {
            print("swizzled")
            method_exchangeImplementations(originalMethod, substitutedMethod)
        } else {
            print("not swizzled")
        }
    }
}

class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let label = UILabel()
        label.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
        label.text = "Hello World!"
        label.textColor = .black

        view.addSubview(label)
        self.view = view
        print("view loaded")
    }
}

// Swizzle
UIViewController.swizzle() // call this in @top of didFinishLaunchingWithOptions

// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

Output:

swizzled

view loaded

This is injected code in view did appear

Now in the substitutedViewDidAppear upper portion inject your counting code as @Rakesha Shastri Suggested, call the updateVisitCount method inside of substitutedViewDidAppear & place the UIViewController.swizzle() in applicationDidFinishLaunchingWithOptions before creating the root window.

Create a static variable. A static variable is a type of class, not object therefore throughout all objects a variable maybe maintained. I think this example may better explain how this works. Click here

In ViewDidLoad method call this function :

func updateVisitingCounter() {

    var counter = UserDefaults.standard.integer(forKey: "firstPageCounter")
    counter += 1
    UserDefaults.standard.set(counter, forKey: "firstPageCounter")

}

You may set declare variables at project scope "outside of classes"

    var vc1Count = 0
    class oneV: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            vc1Count = vc1Count+1
        }
    }

    var vc2Count = 0
    class twoV: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
            vc2Count = vc2Count+1
        }
    }

you can also declare these variables at a common place.

As per your requirements its kind of Analytics on app usage. You can implement in 2 ways

  1. By storing data with screen visit in local DB and show it on Analysis Page or on summery page.

Sample code for storing Screen details in DB:

==> Create your Entity for Screen capture. ScreenVisit.

==> Store Data with screen name.

let entity = NSEntityDescription.entity(forEntityName: "ScreenVisit", in: context)
let newVisit = NSManagedObject(entity: entity!, insertInto: context)

newVisit.setValue("HomeScreen", forKey: "screenname")
newVisit.setValue("1", forKey: "visited")

do {          
   try context.save()       
  } catch {       
   print("Failed saving")
}

==> Fetch data where you required.

    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "ScreenVisit")
    //request.predicate = NSPredicate(format: <Your Filter Logic>)
    request.returnsObjectsAsFaults = false
    do {
        let result = try context.fetch(request)
        for data in result as! [NSManagedObject] {
           print(data.value(forKey: "screenname") as! String)
           print(data.value(forKey: "visited") as! String)
      }

    } catch {

        print("Failed")
    }
  1. You can use any 3rd party library like Google analytics, Crashlytics for tracking your user actions.

Ref Links :

Firebase iOS analytics

Crashlytics

but as per my experience 2nd way is more convenient and powerful.

All depends on your requirements.

Hope this will helps you to get your user action captured.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM