Swift Firebase viewcontroller only for specific user - ios

In my app I have to validate user generated content, to do that I saw that with the panel of Firebase is not a fast thing, so I searched and I found Firebase FireAdmin, but it's not free and what I want is only change a value of approvation from not to yes (after have seeing content).
It's a good idea to make a viewcontroller hide for all exept from me by checking firauth property of Firebase?
let userID : String = (Auth.auth().currentUser?.uid)!
if userID == myid... { show view controller...
Thanx in advance

No it's not a good idea. This value can be changed or the controller can be access if your code is usafe. The application will be heavier for a controller that will not be used by users.
You have to build an admin interface if you don't want to pay for FirebaseAdmin.
In function of what you are looking for, you can also have a look at Firebase Database where you can read and edit values.

Related

How to make app (with username/password login) know that a user is logged in?

I'm trying to make a login screen and made a database with Firebase by Google. The way I tried to make accounts in database is just by making a new child which is "Users" and then the next child would be a user (which is uniquely defined with a unique username). Then, user has other attributes and an attribute called loggedIn which is set to String 'false' but when on loginScreen login goes successfully set to String 'true'. How can I know after login and when that LoginViewController goes away which account has logged in exactly on that phone (simulator at the time) because there can be more users at one time with the attribute value 'loggedIn' set to 'true' and because of that can't go back to database to check that. I'm really new at this and don't know if this whole approach is okay by making in real-time database something like that and actually checking that by the attribute. Maybe I have to use some kind of a local database or something similar?
Swift 4, iOS development, Xcode 9
If you just want to persist locally the login status you may use UserDefaults. Just have a key called currentUser and set the value as his unique Id.
Once a user logs out just clear that key.
You can also use that to determine whether to launch the login screen when the app opens.
But it may be better to use something like AWS Cognito or similar services to handle user management.
Are you building an iOS app only or a cross-platform project?
I'm not sure this is the perfect answer for you. However, some of my apps use CloudKit and the login is authenticated and only then opens up areas of the app on the user's device. I'm sure if you wanted to check the status of successful logins, the authentication on the cloud could update as confirmation and you could subsequently access the cloud database using the CloudKit Dashboard.
It's quite intuitive and works seamlessly with Xcode.
I have a class called LoginManager, defined as an NSObject. Included in there is an optional String variable called accessToken with setter and getter functions for saving and retrieving my access token, including an option for clearing the token which would be used upon logout. There is also a function to check the status of the key.
var accessToken: String? {
get {
return //key from storage
}
set {
if newValue == nil {
//remove key from storage
} else {
//save key to storage
}
}
}
func isUserLogedIn() -> Bool {
return self.accessToken != nil
}
In my own case, I have an application manager object that changes the root view controller based on this info.
LoginManager.singleton.isUserLogedIn() ? loadMainView() : loadLoginView()
So the resulting view controller is never loaded unless the user is logged in. Is that useful to you?

Is it fine to access NSUserDefaults/UserDefaults frequently?

I have a login view controller in which the user enters their preferences like whether or not he wants to activate certain UI features.
I store these as variables whose getters and setters directly access UserDefaults, here is an example of one of these:
class Preferences {
static var likesSpaghetti : Bool {
set (likesSpaghetti) {
UserDefaults.standard.set(likesSpaghetti, forKey: "likesSpaghetti")
}
get {
return UserDefaults.standard.bool(forKey: "likesSpaghetti")
}
}
}
So that whenever I want to set any of these I simply write something like this:
Preferences.likesSpaghetti = false
Now, my question is: Can I set these variables every time the user flicks the on/off switch or should I keep the preference represented as a local variable and then only set:
Preferences.likesSpaghetti = spaghettiSwitch.isOn
when the user segue's away from the loginViewController? Is every access of UserDefault instant and quick? or is it laggy and should be used mercifully?
Edit after closing this question: So I learned to not prematurely optimize, and that it is probably ok within the scope of a few dozen elements. So I should be fine. I'm going to just update every time the user modifies anything so that my code is a lot easier to read and maintain.
Thanks everyone!
Your code is just fine. Don't worry about such optimizations until you actually encounter an issue. Trust that UserDefaults is implemented smartly (because it is). There is nothing "laggy" about setting something as simple as a Bool in UserDefaults.
You also wish to review another one of my answers which is related to this question: When and why should you use NSUserDefaults's synchronize() method?
Actually userDefaults (it's originally a plist file) is used for this purpose which is storing app settings and that light-wight content creating a variable may consum memory if you have to configure many of them , besides not reflecting the new setting change directly to defaults made by user , may cause un-expectable old settings to happen at the time of change such as a localized alert or part of code (such as push notification callback) that check the same setting where the user thinks it's already reflected
Adding to both #rmaddy #Sh_Khan, if you think about the security aspect of it, NSUserDafault is exactly for the details which is app specific such as settings, preferences or some configurations which are not security sensitive while things like passwords, usernames and sensitive data are not recommended to store in UserDefaults. You should use services like keychain which is encrypted for such data.

When to Grab Data From firebase in Swift (iOS dev)

I'm currently creating an app which stores information in a database which the users device must have in order for certain parts of the app to respond differently.
My question is, when should I be calling for this data from firebase.
e.g.
In one part of my app, the app needs to know if the user is currently "connected" to another user. Currently, it checks this against the database as the user presses on the tab bar icon where this information needs to be known, which takes a couple seconds. (checked in the viewdidload() override func)
Should I be grabbing all data from the database before the first view controller is even displayed?
Is there a way to share this between all the view controllers?
If I could load all data from the database into global variables on the device that all view controllers can see this would seem much easier, however i'm not sure if this is good practice.
What would you recommend?
My database structure:
Basically, right now, when the user opens the app and logs in, I need the 'name' and 'family' of each user to be stored for use across the whole app globally across all classes and view controllers.
In terms of the list. when the user clicks the view controller where the list is, currently i'm just running code like this
self.ref.child("familys").child(email.replacingOccurrences(of: ".", with: "")).child("list").observe(.value, with: { (DataSnapshot) in
if DataSnapshot.hasChildren() == false{
print("No list")
return
}
self.tableList = DataSnapshot.value as! [String]
self.tableView.reloadData()
}) { (Error) in
print(Error)
}
then it goes ahead and updates the list with the array 'tableList'.
This means the first time the user clicks to get to the shopping view, there is some delay before the list populates.
I'm not sure what the standard way is to go about grabbing data like this and when it should be done in a way which minimises data usage and database access frequency.
I think you are on the right track. Although you may think you need all the data stored globally so you can access it from all view controllers, you don't. You can pass the data between viewControllers through segues. If you are making a tab based app, you just pull the data necessary for that ViewController in the viewDidLoad() (just like you are doing).
The name of the game is to structure your Firebase database so that when you pull data, you can pull as little as possible to fill all the fields in the View Controller. Since Firebase uses a JSON structure, there is no shame in saving the same data twice in order to make a search faster.
That being said, I think a currentUser global variable is useful in your case. Assuming you have a current user (one user logged in), I would just create a User class that mimics the Firebase and instantiate one global variable called currentUser. Your currentUser object should contain enough information to go and pull anything you need for filling ViewControllers. For example if your User class has an email attribute, you can do:
self.ref.child("familys").child(currentUser.email.replacingOccurrences(of: ".", with: "")).child("list").observe(.value, with: { (DataSnapshot) in
if DataSnapshot.hasChildren() == false{
print("No list")
return
}
self.tableList = DataSnapshot.value as! [String]
self.tableView.reloadData()
}) { (Error) in
print(Error)
}
Global variables should be avoided when possible, but I think just reducing it to one global variable should be enough to get you going.
As for why you are getting a delay, I'm not sure. When you are pulling that little data, it should be extremely fast. If there really is a noticeable delay when pulling a list of 2 items, the issue might be elsewhere (network, simulator, etc.).

Storing check status of toDo list

I am developing a new screen in my app and I wanted to consult with you the best way to do it.
The new screen is going to be a static checklist and I want the user to check "step-by-step" (i.e. line-by-line) that he completed the step.
I have 2 view controller
VC1 = theme static list
VC2 = step static list linked to each step
--> you click on VC1.Theme1 and then it displays VC2.step1,2,3, etc.. in a static tableview.
What I want to do is:
1. checking steps in VC2 and "keep them in memory"
2. when all steps in VC2 are checked updated the status of the theme in VC1
If for 2. it is a simple calculation I am wondering what would be the best method to store the status of the step completion. I am hesitating between a database (custom) or the phone memory... I have not enough experience to know if there are other options or what is the best practice.
Any advise?
I believe the most simple way is to use UserDefaults.
I usually use it for simple data storage. For a start I think it's a good solution for you. For example you may store an array of Bools which indicates whether steps are checked or not. Or store a counter (int) that will indicate quantity of checked steps and compare it to total of steps in the VC2.
How to write to user defaults:
let defaults = UserDefaults.standard()
defaults.set(yourValue, forKey: "valueKey")
And read:
defaults.value(forKey: "valueKey")
Hope it helps.

Best way to set the currentUserID Using Firebase Auth and Swift

I am building an app using Firebase. I would like to know which is the best way to set a current user session with Swift and Firebase. Should I make a User Object and assign the ID to that object as an attribute and then set it nil when the user logs out? Or is there a simpler way sharing that currentUserID across view controllers?
Firebase comes with solution to this:
let userID: String = FIRAuth.auth()!.currentUser!.uid
print(userID)
Just found out.

Resources