How to show a UIPageViewController only once on first launch - ios

I want to show a tutorial that is a UIPageView only once at the beginning of the first launch.
I am attempting this using this code
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore {
performSegue(withIdentifier: "tutorialtohome1", sender: nil)
}
else {
UserDefaults.standard.set(true, forKey: "launchedBefore")
}
For some reason it's not working with the UIPageController, it works fine with other views.
Just to make clear, I only want this view to appear once, then never again, as it acts as a tutorial.
Any suggestions?
Thanks

You need to check the OBJECT. Not the bool. This is better way to do it. On first run, there are no such key "lauchedBefore". You cannot check boolean value of what's not there.
let launchedBefore = UserDefaults.standard.object(forKey: "launchedBefore")
if (launchedBefore==nil) {
performSegue(withIdentifier: "tutorialtohome1", sender: nil)
UserDefaults.standard.set(true, forKey: "launchedBefore")
}
else {
// already launched, so do nothing.
}

Related

Switch Save user preference

I am trying to send a tag with OneSignal when the switch is turned on, and send request to delete the tag when it is turned off again.
#IBAction func tagGeneral(_ sender: UISwitch) {
if (sender.isOn == true) {
OneSignal.sendTag("General", value: "value")
print("sendtag")
}
else {
OneSignal.deleteTag("General")
print("deletetag")
}
}
This is the code i use for it. Seems to be working but when the user goes to another page the switch is automatically turned off...
How can i fix this?
Regarding #Ryan's comment, Here's an answer:
First. there are many ways to save the user preference, i'll be doing it with UserDefaults() | Edit your button action code:
#IBAction func tagGeneral(_ sender: UISwitch) {
let userdef = UserDefaults.standard
if (sender.isOn == true) {
OneSignal.sendTag("General", value: "value")
print("sendtag")
// user made the choice
userdef.set(true, forKey: "sw_set")
} else {
OneSignal.deleteTag("General")
print("deletetag")
// reset
userdef.set(false, forKey: "sw_set")
}
}
Normally this wouldn't work without this little function, make sure you call this function in your viewDidAppear():
private func init_switch() {
// Thanks #Vadian for the tip
let userdef = UserDefaults.standard
self.yourSwitch.isOn = userdef.bool(forKey: "sw_set")
}
Call it in viewDidAppear():
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
self.init_switch()
}
And let me know if it helped.

performSegue not working FireBase while checking the user is authenticated Swift 3/4

I just finish a tutorial video of letsbuildthatapp about firebase mixed with social login.
I currently trying to perform a segue if the user is already authenticated.
I print something in my if and just after I performSegue with a segue who I know work because I'm using it for a test.
there is my code
func verifDejaConnecter() {
if Auth.auth().currentUser?.uid != nil {
performSegue(withIdentifier: "segueAccueilToPres", sender: nil)
print("test")
} else {
return
}
}
mySegue is created and works but nothing append here.
In the console I can see the test resulting from the print in the if ... but nothing is mooving
Try this:
func verifDejaConnecter() {
if Auth.auth().currentUser?.uid != nil {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "segueAccueilToPres", sender: self)
print("test")
}
} else {
return
}
}
If you want to show a different controller when opening the app if the User is logged in, I would suggest you instantiate a different controller... Heres the code I'm using for this. (In AppDelegate)
if ((Auth.auth().currentUser) != nil)
{
initialViewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarController") as! UITabBarController // or UIViewController depending on your setup.
}
else
{
initialViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginController") as!
LoginController // or your login controller.
}
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
where "LoginController" & "tabBarController" you will need to input these into the storyBoard Identity inspector under Identity, StoryBoard Identity.

Display coach marks view when user launches app for the first time Swift 3

I need to launch a coach marks/tutorial view over a tableview when the user launches the app for the first time. The coach marks will never display again, unless the user deletes and reinstalls the app.
I scoured the internet, but was unable to find a simple solution. Oh, I'm fairly new to Swift, so please be gentle. :)
EDIT:
Here is the what I used. Works great!
override func viewDidAppear(_ animated: Bool) {
if !UserDefaults.standard.bool(forKey: "isSecondTime") {
let launchedBefore = UserDefaults.standard.bool(forKey: "isSecondTime")
if launchedBefore {
print("Not the first launch.")
} else {
let VC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CoachMarksViewController")
self.present(VC, animated: true, completion: nil)
print("This the first launch.")
UserDefaults.standard.set(true, forKey: "isSecondTime")
}
}
}
Probably this is what you need?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated);
let kFirstLaunch = "First_launch"
if (UserDefaults.standard.object(forKey: kFirstLaunch) == nil) {
UserDefaults.standard.set(1, forKey: kFirstLaunch);
//Show your coach marks here
}
}
You should use "UserDefaults" to achieve this. In your "viewDidLoad" method check if a value let's say "isSecondTime == true" (This value you will access from "UserDefaults") then do nothing otherwise in else section show your tutorial and save the value "isSecondTime = true" in "UserDefaults". It will work according to your requirements. Check this code:
if(NSUserDefaults.standardUserDefaults().boolForKey("isSecondTime"))
{
// app already launched
}
else
{
// This is the first launch ever
// show your tutorial.....!
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isSecondTime")
NSUserDefaults.standardUserDefaults().synchronize()
}
For Swift 3:
let launchedBefore = UserDefaults.standard.bool(forKey: "isSecondTime")
if launchedBefore {
print("Not first launch.")
} else {
// // show your tutorial.....!
print("First launch, setting UserDefault.")
UserDefaults.standard.set(true, forKey: "isSecondTime")
}
You should use this little launches manager :)
enum AppLaunchManager {
// MARK: - Private Attributes
private static let launchesCountKey = "LaunchesCount"
// MARK: Public Enum Methods
static func launchesCount() -> Int {
guard let launched = UserDefaults.standard.value(forKey: launchesCountKey) as? Int else {
return 0
}
return launched
}
static func registerLaunch() {
UserDefaults.standard.setValue(launchesCount() + 1, forKey: launchesCountKey)
}
static func isFirstLaunch() -> Bool {
return launchesCount() <= 1
}
}
And in AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
AppLaunchManager.registerLaunch()
return true
}
Then, whenever you need just use:
if AppLaunchManager.isFirstLaunch() {
/* do whatever you need */
}
So you need a bool to indicate whether to show the coach marks/tutorial that persists across the app being terminated and restarted. The first time the app is run the bool will indicate that the coach marks must be displayed then the app will set the bool to indicate that they are no longer required.
To persist the bool you could use UserDefaults to store the bool and read it when the app starts. Here is the link to the Apple documentation on it.
p.s. it might be nice to give the user a way to display them again as they might forget something or just dismiss them without thinking.

First time launch / segue swift

what i am trying to accomplish is once the app is launched it will check for first time use. if it is the first time use it will take you to a view controller to enter credentials, else it will take you to to the main menu of the app. this is what i have so far but every time i launch it will give me a blank page with the error message of "A segue must either have a performHandler or it must override -perform.
" i have both segues linked on storyboard. can any one please steer me in the right direction.
let defaults = UserDefaults.standard
if defaults.string(forKey: "isAppAlreadyLaunchedOnce") != nil{
print("first time")
self.performSegue(withIdentifier: "toToken", sender: nil)
}else{
defaults.set(true, forKey: "isAppAlreadyLaunchedOne")
defaults.synchronize()
print("not first")
self.performSegue(withIdentifier: "toMainMenu", sender: nil)
}
If your segue type is set to be Custom in Storyboard — you have to subclass UIStoryboardSegue with your own logic in order for it to work.
class MySegue: UIStoryboardSegue {
override func perform() {
// your custom transition logic
}
}
Otherwise just use one of the existing presets from iOS SDK.
Your method is very confusing. The way I go about this problem is shown below.
override viewDidLoad() {
super.viewDidLoad
let checkForFirstTimeLaunch = Userdefaults.standard.string(forKey: "Flag")
if checkForFirstTimeLaunch == false {
print("First time launch")
//if user launches app for the first time, it will go here
} else {
//otherwise, it will go here
}
}

Accessing UserDefaults in Swift from other viewControllers

In my application, I use UserDefaults to store the user's login status (whether they are logged in or not), and their username. It works fine in that when I login, close the app, and open it again my app skips the login page and recognizes that I am already logged in. Although, I am now trying to install a logout button to a separate viewController. When clicked, this logout button needs to 1.) Reset UserDefaults.loginStatus to "False" 2.) Reset UserDefaults.username to nil 3.) Perform a segue to the login page.
Here is the related code from my ViewController.swift file. This is the first viewController which controls the loginPage.
import UIKit
import Firebase
let defaults = UserDefaults.standard
class ViewController: UIViewController {
func DoLogin(username: String, password: String) {
//I Am not including a lot of the other stuff that takes place in this function, only the part that involves the defaults global variable
defaults.setValue(username, forKey: "username")
defaults.setValue("true", forKey: "loginStatus")
defaults.synchronize()
self.performSegue(withIdentifier: "loginToMain", sender: self) //This takes them to the main page of the app
}
override func viewDidLoad() {
super.viewDidLoad()
if let stringOne = defaults.string(forKey: "loginStatus") {
if stringOne == "true" { //If the user is logged in, proceed to main screen
DispatchQueue.main.async
{
self.performSegue(withIdentifier: "loginToMain", sender: self)
}
}
}
}
Below is my code in SecondViewController.swift, particularly the logout function.
import UIKit
import Firebase
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let username = defaults.string(forKey: "username") {
checkAppSetup(username: username) //This is an unrelated function
//I included this because this works fine. Proving that I am able to read the defaults variable fine from this other viewController
}
}
#IBAction func logout(_ sender: Any) {
defaults.setValue("false", forKey: "username")
defaults.setValue("false", forKey: "loginStatus")
defaults.synchronize()
performSegue(withIdentifier: "logoutSegue", sender: nil)
}
When the logout function is run, the segue performs fine but the default values do not change. Can someone explain why and what I can do to get around this?
**Side note, I am not actually going to set the defaults to "false" and "false". That is just temporary for while I am debugging this issue.
Several things.
You should be using set(_:forKey:) and object(_:forKey) to read and write key/value pairs to defaults, not setValue(_:forKey). (Your use of defaults.string(forKey: "loginStatus") is correct, however.)
You should probably be writing a nil to the userName key:
defaults.set(nil, forKey: "username")
And your logout IBAction should almost certainly be setting loginStatus to false, not true.
Try changing those things.
Also, there is no reason to call synchronize unless you are terminating your app in Xcode rather than pressing the home button on the device/simulator in order to let it exit normally.
Hey i used the exactly same concept recently :
1) In your initial view, in the viewDidLoad() , check whether somebody is already logged in or not, and only one user can be logged in one device at a time, so we check like
let defaults = UserDefaults.standard
if defaults.object(forKey: "userName") != nil && defaults.object(forKey: "userPassword") != nil
{
let loginObject = self.storyboard?.instantiateViewController(withIdentifier: "YourSecondViewController") as! YourSecondViewController
//As someone's details are already saved so we auto-login and move to second view
}}
2) In your sign in button function , check whatever condition you want to check and then, inside the same, if condition satisfies then save data to userDefaults.
// If no details are saved in defaults, then control will come to this part, where we will save the entered userName and Password
let defaults = UserDefaults.standard
defaults.set(self.enteredUseName, forKey: "userName")
defaults.set(self.enteredPassword, forKey: "Password")
defaults.synchronize()
3) On logout button , delete the userDefaults and load the login view again :
let defaults = UserDefaults.standard
defaults.removeObject(forKey: "userName") //We Will delete the userDefaults
defaults.removeObject(forKey: "userPassword")
defaults.synchronize() //Sync. the defaults.
navigationController?.popToRootViewController(animated: true) //Move Back to initial view.
4) If you are using a navigation control, that you must be using :P then you will surely see the back button which will open the second view if clicked, for that you can hide the navigation bar in viewDidLoad() of your login view
self.navigationController?.navigationBar.isHidden = true

Resources