Как посчитать, сколько раз вызываются все классы

Я хочу, чтобы пользователь мог узнать, сколько раз он посещал каждый класс. Затем сложите итоги с каждой страницы вместе, чтобы сформировать групповую сумму. Я хочу напечатать общую сумму в файле журнала в каждом из двух контроллеров представления. Таким образом, должна быть напечатана только одна строка.

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

person Community    schedule 27.11.2018    source источник


Ответы (6)


Если вы имеете в виду посещение каждого контроллера представления, когда вы говорите посетили каждый класс. Тогда я бы порекомендовал вам сделать это 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()
    }

}
person Rakesha Shastri    schedule 27.11.2018
comment
Второй вариант (более простой) более перспективен, потому что если пользовательский контроллер представления переопределяет метод ViewDidAppear, то переопределенный метод расширения не будет вызываться. - person Ratul Sharker; 27.11.2018
comment
@RatulSharker Да. Расширение нужно использовать осознанно, как первый фрагмент кода. Я просто делаю его короче, не заставляя OP писать его для каждого контроллера представления. Последний из них самый маленький, где OP даже не нужно вызывать метод, а вместо этого просто создать контроллер представления с помощью подкласса. - person Rakesha Shastri; 27.11.2018
comment
OP должен вызывать этот метод расширения в каждом контроллере представления, который есть в проекте. Из мира Objective-C был еще один вариант, такой как метод swizzling, это похоже на черную магию, замена существующих UIViewController viewDidLoad логикой подсчета и регистрация другого метода с исходной реализацией viewDidLoad. Чтобы поддерживать согласованность жизненного цикла, используйте вызов нового зарегистрированного метода в новой реализации viewDidLoad. Это немного сложно, но OP не нужно вручную вставлять какой-либо код в существующие viewControllers. - person Ratul Sharker; 27.11.2018

Самым автоматическим решением было бы внедрить вызов учета в viewDidLoad без замены исходного viewDidLoad.

Здесь для демонстрации я создал образец игровой площадки.

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, вызовите метод updateVisitCount внутри substitutedViewDidAppear и поместите UIViewController.swizzle() в applicationDidFinishLaunchingWithOptions перед созданием корневого окна.

person Ratul Sharker    schedule 27.11.2018

Создайте статическую переменную. Статическая переменная - это тип класса, а не объекта, поэтому во всех объектах может поддерживаться переменная. Я думаю, что этот пример может лучше объяснить, как это работает. Нажмите здесь

person vi_ral    schedule 27.11.2018
comment
Вы потеряете информацию после закрытия приложения. - person Rakesha Shastri; 27.11.2018
comment
Да, вы потеряете эту информацию, когда приложение будет закрыто, но это очень распространенная проблема. Чтобы сохранить этот уровень базы данных, можно использовать. Спасибо. - person vi_ral; 27.11.2018
comment
Это хорошее чтение. stackoverflow.com/questions/16407594/ - person Rakesha Shastri; 27.11.2018
comment
Интересно NSUserDefaults кажется хорошим способом хранения информации, связанной с приложением. Проголосуйте за мой пост, если считаете, что это хорошее решение :) - person vi_ral; 27.11.2018
comment
Это не для этого варианта использования. Извиняюсь. Что я и пытался донести в своем первом комментарии. - person Rakesha Shastri; 27.11.2018

В методе ViewDidLoad вызовите эту функцию:

func updateVisitingCounter() {

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

}
person amin    schedule 27.11.2018
comment
Что происходит, когда представление уже загружено, и вы снова и снова посещаете его, не загружая? Это еще надо посчитать. - person Rakesha Shastri; 27.11.2018
comment
поэтому вы должны использовать viewWillAppear - person amin; 27.11.2018

Вы можете установить переменные объявления в области проекта «вне классов».

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

вы также можете объявить эти переменные в обычном месте.

person Abu Ul Hassan    schedule 27.11.2018

В соответствии с вашими требованиями это своего рода аналитика использования приложения. Вы можете реализовать 2 способами

  1. Сохраняя данные о посещении экрана в локальной базе данных и отображая их на странице анализа или сводной странице.

Пример кода для хранения сведений об экране в БД:

==> Создайте свой объект для захвата экрана. СкринПосетить.

==> Хранить данные с псевдонимом.

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

Crashlytics

но по моему опыту 2-й способ удобнее и мощнее.

Все зависит от ваших требований.

Надеюсь, это поможет вам зафиксировать действия пользователя.

person CodeChanger    schedule 27.11.2018
comment
Это перебор ИМО. - person fulvio; 27.11.2018