Add analytics event to log each ViewController's name in the project - ios

I have a project in which I need to log an analytics event whenever any View Controller (log the name of the View Controller) comes on screen.
I was trying to avoid littering all of my existing View Controller classes with call to the analytics SDK.
I tried making an AnalyticsViewController and all my View Controllers would subclass this View Controller, and then I add analytics event in AnalyticsViewController class's viewDidLoad method. But the problem with this approach is that AnalyticsViewController does not which child View Controller is the call coming from.
I am using Swift 3.0. I believe that Swift with its powerful language features should be able provide me with an abstraction of some sorts.
Is there any way through this problem without littering all the View Controllers?

You were on the right track. Making a UIViewController parent class is a good idea.
In viewDidLoad method you can just add this:
let className = NSStringFromClass(self.classForCoder)
It will give you the name of current loaded view controller and then you can use that name in your event to specify which view controller was actually loaded.
Edit: added example.
So your parent's viewDidLoad would look something like this:
override func viewDidLoad() {
super.viewDidLoad()
let className = NSStringFromClass(self.classForCoder)
sendEvent(withViewControllerName: className)
}

The answer given by #JPetric is an amazing starting point. I just had to do a little modification to get it to work.
I've put this in my AnalyticsViewController to retrieve the name of the current subclass.
private func currentClassName() -> String? {
return NSStringFromClass(self.classForCoder).components(separatedBy: ".").last
}

Related

Navigate to UIViewController in Swift 2.3

I am trying to navigate to a UIViewController using Swift 2.3. To be more precise, I am trying to reload the UIViewController that is currently active. I do not know which view the user currently has active, so this must be defined dynamically.
I have tried several approaches, but they all result in either compile or runtime errors.
Is something like this possible?
let activeViewIdentifier = ??? // Get currently active view identifier as a string
self.performSegueWithIdentifier(activeViewIdentifier, sender:self)
You can get like this :
Objective-C :
self.navigationController.topViewController.restorationIdentifier
Swift :
self.navigationController?.topViewController?.restorationIdentifier
I think you have some issues with your architecture; it's not the best approach to reload just everything on some View Controller you can chose;
Much better way of thinking is to determine, what exactly you want to reload and add methods to reload only thus things
Anyway, if my answer hasn't assure you, consider replacing existing view controller with new and presenting it with some animation, or without it; so your general algorithm may look like this:
Get new VC from storyboard, or creating new instance, if you don't prefer to use it
Push it over your existing controller
Reload stack of navigation controller, in which you are now
you can try this
let activeViewIdentifier = self.navigationController?.childViewControllers[(self.navigationController?.childViewControllers.count)!-1]
You can use the restorationIdentifier, it's right above the Storyboard identifier and it's a UIViewController property.
let activityIdentifierStr = activeViewIdentifier?.restorationIdentifier
self.performSegueWithIdentifier(activityIdentifierStr!, sender:self)

Duplicate Button actions on different View Controllers?

I have a button on one of my view controllers which controls a score action (counter).
Can someone help me duplicating the button and the action it takes and place the duplicate on a separate ViewController?
I need this for a workout Application i'm making and I want to get the action Proof of concept complete before I implement it into my App.
I have attached my Xcode Project with the stage I am now on.
Ive tried passing the name of the action button from the main VC to the newest but I've had no luck.
https://github.com/Mulreany93/NewVCActionButton
I saw in your GitHub that you have an empty class called ViewControllerNewButton, which inherits from UIViewController. I suggest making your scorebutton into a new class called something like e.g. ScoreButton, which should inherit directly from UIButton - class ScoreButton: UIButton {...} Then in each View Controller you can create your scorebutton: let scoreButtonTest = ScoreButton() and then you can use e.g. conversion functions like scoreButtonTest.someConversion() from your ScoreButton class.
If I am on the wrong track, feel free to comment but as far as I can tell you are just trying to use your button in multiple VCs and that's a good place to try inheritance.
Edit for clarification:
class ScoreButton: UIButton {
func someConversion() {
...
}
}

show a view on 2 viewcontrollers

I'm looking for a way to show a UIView "InventoryView" in 2 view controllers.
I'm working on an inventory system for my game that I trying to make but I need to be able to access it from my main view, where it will go to a InventoryViewController (in this ViewController is my InventoryView) but I also need to be able to access the InventoryView from my BattleViewController where it does not go to my InventoryViewController but where it print the InventoryView on my BattleViewController so I can access everything durning the battle.
Example:
(evrything is dragand drop, the UIView and the UIButtons)
InventoryViewController
class InventoryViewController: UIViewController {
class InventoryView: UIView {
//here are some UIButtons and labels
}
}
BattleViewController
class BattleViewController: UIViewController {
class InventoryView: UIView {
//it should print the Inventory Screen on my BattleViewController
//here are the same properties as it shows in the InventoryViewController
}
}
This is a great example to look at the way OOP programming works best.
Ask yourself the following questions:
What is the purpose of the view?
Are the interactions on the view homogenous across all the instances? (touch events, specific behavior, etc...)
What is the minimum amount of information you need to make the view look the way you want?
Once you have those answers, you can approach the concept of reusability of views safely.
The way to go about it is to subclass UIView, create the necessary elements of your view, setup your constraints (still in the view, either in a nib or programmatically), and implement any behavior that will be consistent across views (For example if the view is a segmented control, every time you click a segment all the others go grey and the one you clicked go blue. Since that's the primary purpose of the segmented control, the code for it should belong to the segmented control).
Chances are you will find the docs very useful: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/
Lastly write a setup method that takes all the information you need and sets up all your graphical elements accordingly. Remember, views should never own their data (they should be templates, the controller will provide the data).
I have no idea what you view looks like but I assume the inventory is represented as an object. Then something like could be a good start:
class InventoryView: UIView {
var inventory: Inventory? {
didSet {
if let newInventory = inventory { //in case we set it to nil
setup(withInventory: newInventory)
}
}
}
private func setup(withInventory inventory: Inventory) {
//do your setup here
}
}
Then in your controller you can call:
let inventoryView = InventoryView()
inventoryView.inventory = myPlayer.inventory
You cannot use a view in two places, at least not within the UI. Every view can be added to only one super view at a time.
If you need the same contents to be displayed twice, create a UIViewController class which's view contains the common UI, create two of those and add them to your UI.

when to use viewDidLoad

I am new to both iOS development and programming in general. I need some clarification as to what sort of things should be declared in the viewDidLoad function of a UIViewController subclass
Thanks
In order to properly understand what viewDidLoad does, you should understand the View Controller Lifecycle. The best point to start is reading the Apple Documentation, e.g. the learning guides for developing iOS Apps: https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/Lesson4.html
Declare elements that don't need to be refreshed or recreated when the view reloads. For instance, viewDidLoad is called only when it is created while viewDidAppear will be called every time the view is shown.
Read up on some apple docs.
Everything you write inside the viewDidLoad function will run the the View(which can be TableView, ViewController & more..) is loaded.
For example, if you got a label called 'label' and you want to set it's by the code so you type:
override func viewDidLoad() {
super.viewDidLoad()
label.text = String("any text here")
}
and then the text of the label will change when the View will load.

Best design/pattern to use for first-use tutorial in app?

The background:
I have an app with 5 tabs. The first time a user navigates to each tab, I would like to show a one-time "tutorial". I intend to do this by creating a "TutorialViewController" that will handle displaying these "tutorial" views and will have buttons for next/back etc...
The problem:
I'm not sure the best pattern to use for implementing the logic for whether or not to show these screens and instantiating the "TutorialViewController" to display them. The goal is to have a single line of code (a single method call) that would show the tutorial if necessary. I'm trying to avoid duplication of code across the 5 view controllers. The problem is where/how to implement this single method. As a class method on TutorialViewController? As a global C function?
Things I've considered:
1) Implementing a class method on TutorialViewController called "displayTutorialIfNecessary". In this case, each view controller that has a tutorial would call this class method from their "viewDidAppear" methods. This class method would check to see if the tutorial has already been shown, and if not, it would instantiate a TutorialViewController object to handle to display it. In this option, I guess I would have to pass in "self" from each calling view controller and the class method would use that to display the TutorialViewController.
2) Implementing a class method on TutorialViewController called "tutorialShouldBeDisplayedForScreen: ". In this option, each calling view controller would call this method, and if it returns true, each vc would instantiate and present the "TutorialViewController" which would handle displaying the tutorial.
I'm sure there is a "best practice" or a pattern that fits this scenario, but I'm not sure what the best implementation is. Thanks in advance for your recommendations.
To summarize: Instead of having something like this in each view controller:
if ([TutorialViewController shouldDisplayTutorialForScreen:<someEnum>])
{
TutorialViewController *myTutorialVC = [[TutorialViewController alloc] init];
[self displayModalViewController: myTutorialVC];
}
I'd like something more like this:
[FirstUseViewController displayTutorialIfNecessaryForScreen: <someEnum> forParentViewController: self];
store the tutorial has shown state into NSUserDefaults and use factory method design pattern to let each UIViewController you'll need create and return tutorial UIViewController like:
- (UIViewController *)tutorialVC {
return [[MYHomeScreenTutorialVC alloc] init];
}

Resources