How to make a screen show only on initial launch - ios

I'm trying to make the intro screens for my app - namely the terms of service screen that all users have to agree to the 1st time they download and run the app. obviously, once the users agree, i dont want to show them it again every time they log on the app. what is the best way to go about doing this? I've been reading about NSUserDefaults, but am stuck pretty much after that.

In your AppDelegate or whichever class needs to check for first-run status:
Bool isFirstRun = !NSUserDefaults.standardUserDefaults().boolForKey("kAppPreviousLaunchKey")
NSUserDefaults.standardUserDefaults().setBool(true, forKey:"kAppPreviousLaunchKey")
if isFirstRun {
// React here
}

Play with this piece of code in the AppDelegate Class
let launchedBefore = NSUserDefaults.standardUserDefaults().boolForKey("launchedBefore")
if launchedBefore {
print("Not first launch.")
}
else {
print("First launch, setting NSUserDefault.")
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "launchedBefore")
}

Related

Firebase Phone Authentication - Long Delay & Multiple OTPs

I'm working on an iOS app project that involves Firebase's phone authentication. I have it working fine on simulator, my iPhone, and my iPad. However, now that I am in the TestFlight stage , my external testers are experiencing long delays in receiving their OTPs as well as receiving duplicates when they reach the ViewController where they enter the OTP code (This is probably due to them hitting the button multiple times).
I also have APNs enabled and working properly.
I don't have much code to share as I followed Firebase's documentation.
What could be some reasons for a long delay in receiving the OTP code from Firebase? I will be including an activity spinner in the project when users tap the sign-in button. However, I also don't want it to be spinning for a minute as users wait for their OTP.
#objc func phoneSignIn() {
guard let phoneNumber = startVerificationView.phoneNumberTextField.text else { return }
let completePhoneNumber = "+1\(phoneNumber)"
Auth.auth().settings?.isAppVerificationDisabledForTesting = isVerificationDisabled
PhoneAuthProvider.provider().verifyPhoneNumber(completePhoneNumber, uiDelegate: nil) { (verificationId, error) in
if error == nil {
guard let verifyId = verificationId else { return }
UserDefaults.standard.set(verifyId, forKey: "verificationId")
let vc = CheckVerificationViewController()
vc.modalPresentationStyle = .fullScreen
vc.completePhoneNumber = completePhoneNumber
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
Also isVerificationDisabled is set to false.

UserDefaults.standard.string() returns nil

I "inherited" an iOS Xcode Project in Swift. I've never programmed in Swift or used Xcode before. I copied the project from one user account to another and checked it into a git repo.
Now I'm araid this (the copying, permissions ?) might be the cause for the App not being able to read its settings properly. Because UserDefaults.standard.string(forKey: "pref_Foo") returns nil although in the Settings.Bundle's Root.plist there's clearly a pref_Foo identifier.
The App has worked before, so I don't see where this suddenly comes from.
Since I'm not too familiar with XCode all I did up til now was debug into the Application to see that UserDefaults.standard.string(forKey: "pref_Foo") is nil.
How could I approach this problem?
Thank you!
EDIT: This is part of my code in ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
loadSettings()
...
}
func loadSettings()
{
if(UserDefaults.standard.object(forKey: "pref_Foo") == nil)
{
printf("Error")
}
}
You should use below code with validation, first delete app and install again. then use, you will get success.
var UserStatus:String {
get{
return UserDefaults.standard.object(forKey: "pref_Foo") as? String ?? "0"
}
set(status){
UserDefaults.standard.set(status, forKey: "pref_Foo")
UserDefaults.standard.synchronize()
}
}
Use of code is as below.
if (UserStatus == "pref_Foo"){
self.logoutSuccess()
} else {
self.loginSuccess()
}
Update or set value is so simple in one line code as given below.
UserStatus = "pref_Foo"

Why photos from gallery does not appear after permissions giving?

I'm using this GitHub project's controller for displaying user's Photo Gallery inside of UICollectionView. Everything is okay there, but except one: If I run it for the first time, it asks me about permissions. I accept it, but after that I cannot get my images from the gallery. It displays nothing.
But when I close my app and run again it can get my photos from the gallery. So, this problem appears just on the first launch.
Can anyone help me, how can I solve it?
UPDATE
I suppose, that this observer works incorrect:
func photoLibraryDidChange(changeInstance: PHChange) {
let changeDetails = changeInstance.changeDetailsForFetchResult(images)
self.images = changeDetails!.fetchResultAfterChanges
dispatch_async(dispatch_get_main_queue()) {
// Loop through the visible cell indices
let indexPaths = self.imagesCollectionView.indexPathsForVisibleItems()
for indexPath in indexPaths as [NSIndexPath]! {
if changeDetails!.changedIndexes!.containsIndex(indexPath.item) {
let cell = self.imagesCollectionView?.cellForItemAtIndexPath(indexPath) as! ImagesCollectionViewCell
cell.imageAsset = changeDetails!.fetchResultAfterChanges[indexPath.item] as? PHAsset
}
}
}
}
So, I give permissions, but it doesn't show me my photos. For this I need to relaunch my app
If you want any code - I can share it. But I'm using the above github controller which I've attached above.
Since it works correctly when you relaunch the app it sounds like you are probably asking for permissions at the same time you are displaying the view controller/collection view. The problem is that the collection view doesn't know to reload once the user has selected to give your app access to their photos. In the PHPhotoLibrary.requestAuthorization call back you need to tell your view controller/collection view to reload once they have Authorized your app. Small example below:
PHPhotoLibrary.requestAuthorization { status in
switch status {
case .Authorized:
/* RELOAD COLLECTION VIEW HERE */
case .Restricted:
<#your code#>
case .Denied:
<#your code#>
default:
// place for .NotDetermined - in this callback status is already determined so should never get here
break
}
}

Swift: Hide a View Controller after first time use

In swift I am making a app where it asks for a code before going to the actual app. I only want this to be showed once. How do I have this page only showed the first time then they enter the code and they only have to do this once then when they use the app again they don't need to enter a code. Thanks.
Your best shot is NSUserDefaults. Save a flag (a boolean) in NSUserDefaults to indicate whether it is the first time the user has opened the app.
let userDefaults = NSUserDefaults.standardUserDefaults()
if userDefaults.valueForKey("IS_FIRST_TIME") as? Bool != nil {
// First time, do something...
// ...
// ...
// Now, save a flag to indicate that this was the first time.
userDefaults.setValue(true, forKey: "IS_FIRST_TIME")
userDefaults.synchronize() // Needed to save the new value.
}

Swift Problems - NSUserDefault and Settings Bundle not responding

So I had set up a settings bundle to just do one thing. Allow the Users to choose between the The TouchUI and GestureUI in my app and for some odd reason, I am unable to get the Settings Bundle to control it. It stays with one and doesn't switch even when I have the If else Statement. originally I had var touchCheck = userDefaults.boolForKey("myGestureEnabledDisabled") but it didn't change boolean at all when i keep closing app(Multitask > SwipeUp app) and re running the app via springboard. The Settings App could have the bundle at NO but log says gestures are on. After watching a Tutorial, i changed boolForKey to valueForKey which causes the build to fail and there is no error in the code the way i have it below.
override func viewDidLoad() {
var userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.synchronize()
var touchCheck = Bool(userDefaults.valueForKey("myGestureEnabledDisabled"))
if touchCheck {
whenGuestureIsEnabled()
} else {
whenGestureIsDisabled()
self.navBar.hidden = false
}
}
func whenGuestureIsEnabled() {
NSLog("Gesture is suppose to be on")
}
func whenGestureIsDisabled() {
NSLog("Gesture is OFF")
}
Maybe from what I was thinking, I shouldn't do this in UIViewController but I had seen this in action in a youtube tutorial and it was in OBJ-C.
You should cast to bool, not to create a new one:
//notice (Bool) cast in the beginning
var touchCheck = (Bool)userDefaults.valueForKey("myGestureEnabledDisabled")

Resources