【问题标题】:How to count how many times all classes are called如何计算所有类被调用的次数
【发布时间】:2019-04-28 19:04:45
【问题描述】:

我希望用户能够知道他们访问了每个班级的次数。然后将每个页面的总数加在一起,形成一个组和。我想在两个视图控制器中的每一个的日志文件中打印总和。所以应该只打印一个字符串。

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")
    }
}

【问题讨论】:

    标签: ios swift userdefaults


    【解决方案1】:

    根据您的要求,对应用使用情况进行分析。您可以通过 2 种方式实现

    1. 通过将屏幕访问的数据存储在本地数据库中,并将其显示在分析页面或摘要页面上。

    在 DB 中存储屏幕详细信息的示例代码:

    ==> 为屏幕截图创建实体。 屏幕访问。

    ==> 使用屏幕名称存储数据。

    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")
    }
    

    ==> 在需要的地方获取数据。

        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. 您可以使用任何第三方库(例如 Google Analytics、Crashlytics)来跟踪您的用户操作。

    参考链接:

    Firebase iOS analytics

    Crashlytics

    但根据我的经验,第二种方式更方便、更强大。

    一切都取决于您的要求。

    希望这将帮助您捕获用户操作。

    【讨论】:

    • IMO 太过分了。
    【解决方案2】:

    如果您的意思是访问了每个视图控制器,那么当您说访问了每个类时。那么我建议你这样做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)
        }
    
    }
    

    为了更简单,您可以在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)
        }
    
    }
    

    或者,如果您创建的每个视图控制器都需要这个,那么您可以创建一个基本视图控制器,您可以在任何地方使用它而不是 UIViewController

    class BaseViewController: UIViewController {
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            updateVisitCount()
        }
    
    }
    

    【讨论】:

    • 第二个选项(更简单的一个)更有希望,因为如果自定义视图控制器覆盖ViewDidAppear 方法,那么扩展的覆盖方法将不会被调用。
    • @RatulSharker 是的。扩展必须像第一个代码剪辑器一样有意识地使用。我只是通过不让 OP 为每个视图控制器编写它来缩短它。最后一个是最小的,OP 甚至不需要调用该方法,而是使用子类创建一个视图控制器。
    • OP 必须在项目中的每个视图控制器中调用此扩展方法。在 Objective-C 世界中,还有另一个选项,比如方法调配,就像黑魔法一样,用计数逻辑替换现有的 UIViewControllerviewDidLoad,并使用 viewDidLoad 的原始实现注册另一个方法。为了保持生命周期的一致性,在新的viewDidLoad 实现中调用新注册的方法。这有点复杂,但是 OP 不必在现有的 viewControllers 中手动插入任何代码。
    【解决方案3】:

    创建一个静态变量。静态变量是一种类,而不是对象,因此在所有对象中都可以维护一个变量。我认为这个例子可以更好地解释它是如何工作的。点击here

    【讨论】:

    • 一旦应用关闭,您将丢失信息。
    • 嗯,是的,当应用程序关闭时,您会丢失该信息,但这是一个非常常见的问题。为了持久化,可以使用数据库层。谢谢。
    • 有趣的 NSUserDefaults 似乎是存储应用相关信息的好方法。如果您认为这是一个很好的解决方案,请支持我的帖子:)
    • 不适用于这个用例。对不起。这就是我在第一条评论中想要表达的意思。
    【解决方案4】:

    在 ViewDidLoad 方法中调用这个函数:

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

    【讨论】:

    • 当视图已经加载并且您一次又一次地访问它而不加载它时会发生什么?这仍然需要计算。
    • 所以你应该使用 viewWillAppear
    【解决方案5】:

    最自动化的解决方案是在viewDidLoad 中注入会计调用,而不替换原始 viewDidLoad

    在这里我创建了一个示例 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()
    

    输出:

    混搭

    查看已加载

    这是在视图中注入的代码确实出现了

    现在在substitutedViewDidAppear 上部注入您的计数代码作为@Rakesha Shastri 建议,在substitutedViewDidAppear 内调用updateVisitCount 方法并在创建根窗口之前将UIViewController.swizzle() 放入applicationDidFinishLaunchingWithOptions

    【讨论】:

      【解决方案6】:

      您可以在“类之外”的项目范围内设置声明变量

          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
              }
          }
      

      你也可以在一个共同的地方声明这些变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-01-09
        • 2022-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-10
        相关资源
        最近更新 更多