I was playing around with Firebase Auth and I noticed all FirebaseAuth.User instances have a method called setValue(value:forKey:). I searched around in the "Manage Users" section of the Firebase Auth Docs but found no reference of it.
I wanted to know what it does. I'm guessing you can use it to set some special value (somewhat like a property) to a FirebaseAuth.User. If that's the case would it be useful for storing additional data associated with a user such as "preferredGenres" or "emergencyNumber"?
Please let me know what setValue(value:forKey:) does, what are its uses, and if my assumption is correct.
Thanks in advance!
As you can see from User class declaration:
class User : NSObject, UserInfo it inherited from an NSObject which has setValue(value:forKey:) method. Within NSObject this method allows to set any properties via String key. Apple docs are here: setValue(forKey:)
So in common you can just access and mutate all the existing User properties but in a less safe manner.
Related
Description + sample + explanation: (You can skip to the question section)
I'd like to make an object instance, which can be implemented by different implementations, depend on a condition (the internet status).
Simple declaration
#interface LoginController : NSObject
/** The currently logged-in User. Nil if not logged-in yet. */
#property (strong, nonatomic) User *currentUser;
// Singleton object
+ (instancetype)shareInstance;
/** Abstract methods, will do nothing if call directly. Use inheritance implements (Online/Offline) instead. */
- (User *)loginByEmail:(NSString *)email password:(NSString *)pwd;
#end
#interface LoginControllerOnline : LoginController
// Login will call request to server.
#end
#interface LoginControllerOffline : LoginController
// Login will check data in coredata.
#end
The LoginController's login method actually do nothing (return nil). Instead, the inherited class (Online/Offline) overwrite the parent login's method, with different implementations (as in comments)
And then, I have a manager to define which class should be in use:
#implement InternetManager
+ (LoginController *)loginController
{
return [self hasInternet] ? [LoginControllerOnline shareInstance] : [LoginControllerOffline shareInstance];
}
+ (BOOL)hasInternet
{
// Check with Reachability.
}
#end
This work. But it's not the mechanism I'd like to achieve.
This mean I have 2 instances of inherited LoginController instead of 1.
When internetStatus change from offline to online, I'd like to re-login online (to get session/oauthToken...). But, I'll have to do many things (copy user, change instance, check retained...) before I can actually call from login online
QUESTION:
Is there a way for me to create only one instance of LoginController, which hold the same properties (User), but can has different (dynamic) implementations (Online/Offline)?
Update question:
Quote from Apple's Dynamic typing:
The isa Pointer:
Every object has an isa instance variable that
identifies the object's class. The runtime uses this pointer to
determine the actual class of the object when it needs to.
So, is there a way for me to change this isa pointer of an object instance?
It sounds like the real problem is that you've given these things direct primary ownership of state that you actually don't want them to own — factor it out. There's no copying, just give each an instance of the thing that marshals sate at -init and allow them to talk to it.
Then just do the normal programming thing when you want to do either one thing or another based on a condition: use an if statement.
So, I don't think use of the dynamic runtime is appropriate. However, academically, supposing an interest:
If you really must, use object_setClass, which "[s]ets the class of an object", answering your actual question. Obviously you need the storage to be compatible, so probably your subclasses shouldn't declare any properties or instance variables.
A commonly-discussed alternative for this general area is not changing the class of an existing instance but changing the methods that are a member of the class. So you'd have two alternative implementations of -loginByEmail:password: and set which was the one that actually responded to that selector dynamically. But there's really no advantage over just using an if if you have access to the source code and a bunch of disadvantages around its generally indirect, opaque nature. The whole thing is usually known as swizzling. class_replaceMethod is the key component but just search for swizzling.
I have this use case where a model object (e.g. class User) has few methods.
Some of the methods in the class require authentication (e.g. getProfile, getFriends,...).
class User{
var loginDelegate:LoginDelegate
func getProfile{
HTTPAsync.getProfile(payload){response in
if response.status == 401 {
login(delegate)
}
}
func getFriends{
//similar code as above
login(delegate)
}
Once, user is successfully logged in, I want to call respective functions (getFriends, getProfile, whichever invoked login).
I have been thinking to use delegate pattern. But since my class (user) has multiple methods that require login, I need to pass some data to delegate, which must be read after user is logged in to call the appropriate method.
I am new to Swift, and was wondering if I am going in the right path. Is there any other obvious way to achieve this pretty common problem.
In my app, use a Url whiteList to solve this problem,
For example, the Url inside the user authentication interface which contains "/users/" this string (or other strings), when the user is not logged in and used a request for such a Url to send out a notification, by a unified class to receive this notification,then Pop up Login box
I am new to Swift, and was wondering if I am going in the right path. Is there any other obvious way to achieve this pretty common problem.
Yes there are a couple of ways you might choose to solve this. e
Define getter methods on your delegate protocol, if it is not your own delegate protocol you can use an extension to extend it's functionality.
Create an Enumeration as an instance variable so you can set an enumeration value with in the login method that your other methods can access after the login method finishes.
Change the login method to accept more parameters and returns a value\object.
For example:
login(delegate: LoginDelegate, dictionaryOfOtherStuff: [String :AnyObject]?) -> (value_1: String, value_2 : [int])
I can only give an example since you have not stated exactly what needs to be available after the login method is called.
I am creating a set of API and some users have suggested that I use id type for a particular method that can accept custom object (defined by the API) or string instead of creating two versions. Is the use of id type in method a good or acceptable practice? Does Apple do it with their any of their API?
That would be very poor practice. If you're creating an API you need to retain full control, and allowing users to pass any object to your method at which point you would have to cast it to that object or string you mentioned could be fatal depending on what's passed. Creating two methods with different parameters is not only okay, but follows the tenets of polymorphism to the T.
Accepting id is not in itself good or bad practice. How much manual procedural if/then/else/if/then/else nonsense will you acquire? If quite a lot then something is wrong.
Put another way: if the conditional logic related to different kinds of object ends up being implicit, via the Objective-C dispatch mechanisms, then the design is good. If you end up impliedly reimplementing dynamic dispatch then you've gone completely wrong.
Apple does it frequently. Just off the top of my head there are:
as per Nikolai's comment, all the collection types: set, dictionary, array, etc.
anything that takes %# as a format specifier: NSLog, certain methods on NSString, etc.
anything that still uses an informal protocol.
anything in or semi-close to the runtime like key-value coding.
archiving and the user defaults.
anywhere that storage is offered for your own use — the hardy userInfo on NSTimer and the rest.
anywhere that target/action is used — all UIControls, the notification centre, etc.
As per my comment, suppose your custom class had this method:
- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding
And suppose it were the only method being called by whomever is being passed either a string or your custom object. Then id would be the right choice, since you'd have in effect implemented an informal protocol, and the thing being passed an object genuinely doesn't care whether it's a string or not. The only contractual requirement is the informal protocol and the protocol is informal i.e. has no footprint on the type syntax.
Conversely, suppose your custom class had no methods in common with NSString and your code just looked like:
- (void)myMethod:(id)object
{
if([object isKindOfClass:[NSString class]])
[self myMethodOnString:object];
else
[self myMethodOnCustomClass:object];
}
Then id would be inappropriate. You're just obscuring what the method does and implicitly reproducing work that's built into the runtime anyway.
How do you use UILexicon in Objective-C? I find the documentation Apple provides is extremely unhelpful.
What does it do? Does it return a dictionary or proper spellings of words? Or do I provide a word like "hellllo" and it matches it with the proper spelling "Hello" and returns that as a string?
Any help would be appreciated.
requestSupplementaryLexiconWithCompletion:
Here's my error report, but obviously I'll have errors because I'm completely guessing how to use the function, no clue what goes inside the block statement (because the docs (at the time) don't say! (Beta 4 docs)) Hahahah!
I've never used this feature, but a quick web search for "UILexicon" landed me in Apple's documentation; reading and following links from there filled in the picture pretty quick.
App Extension Programming Guide has a quick explanation of what lexicons are for:
Every custom keyboard (independent of the value of its RequestsOpenAccess key) has access to a basic autocorrection lexicon through the UILexicon class. Make use of this class, along with a lexicon of your own design, to provide suggestions and autocorrections as users are entering text.
Clicking the UILexicon link on that page took me to the reference doc for that class, which explains that it's a read-only list of Apple-provided term pairs. Each of its entries is a UILexiconEntry object -- the docs for that class say it provides a userInput (what the user typed, e.g. "ipad") and a documentText (what to substitute for it, e.g. "iPad"). Since those classes are read-only, it follows that they're probably not a way for you to provide your own autocorrection pairs -- as stated in the docs, they're for supplementing whatever autocorrection system you implement.
At this point, I don't even have to look at the doc for requestSupplementaryLexiconWithCompletion: to get a good idea how to use it: just the declaration tells me:
It's a method on UIInputViewController, the class I'd have to subclass to create a custom keyboard. Somewhere in that subclass I should probably call it on self.
Its return type is void, so I can't get a lexicon by assigning the result of a requestSupplementaryLexiconWithCompletion call to to a variable.
It calls the block I provide, passing me a UILexicon object as a parameter to that block.
It's got words like "request" and "completionHander" in it, so it'll probably do something asynchronous that takes awhile, and call that block when it's done.
So, I'm guessing that if I were writing a custom keyboard, I'd call this method early on (in viewDidLoad, perhaps) and stash the UILexicon it provides so I can refer to it later when the user is typing. Something like this:
#property UILexicon *lexicon;
- (void)viewDidLoad {
[super viewDidLoad];
[self requestSupplementaryLexiconWithCompletion:^(UILexicon *lexicon){
self.lexicon = lexicon;
}];
}
Because it's unclear how long requestSupplementaryLexiconWithCompletion will take to complete, any place where I'm using self.lexicon I should check to see if it's nil.
Back in the App Extension Programming Guide, it lists "Autocorrection and suggestion" under "Keyboard Features That iOS Users Expect", right before saying:
You can decide whether or not to implement such features; there is no dedicated API for any of the features just listed
So it sounds like autocorrection is something you have to do yourself, with your own UI that's part of the view presented by your UIInputViewController subclass. The API Quick Start for Custom Keyboards section in the programming guide seems to hint at how you'd do that: use documentContextBeforeInput to see what the user has recently typed, deleteBackward to get rid of it, and insertText: to insert a correction.
I am trying to create a custom popup view that can be called from multiple view controllers, but im having some trouble.
I'm able to get it to work fine as long as I write and call a "presentPopup" method from within the viewController itself. Rather then writing an individual method in each VC, i'd much prefer to write a method in a separate class and just pass parameters to personalize it.
Anyway, whenever I try to do so, I keep getting the famous "this class is not key value coding-compliant for the key" error. Just wondering if anyone had any insights as to HOW to make the class key value coding compliant? Or how to go about this in general?? Thanks!!
There is a simple explanation at the end of this answer, but I've seen a few similar questions recently so I thought I'd give a bit of background.
The error should also be telling you which key the class is not key value coding compliant for. The phrasing of your question suggests that you think there is some general bit of code you can add to make a class "key value coding compliant". This isn't the case.
All cocoa / cocoa touch objects are capable of performing key value coding operations. KVC allows you to reach accessor methods by using valueForKey: or setValue:forKey: instead of using the accessor methods directly.
The error you are seeing will be along the lines of:
XXX - this class is not key value coding compliant for key YYY.
XXX is the class in question, YYY is the key. So somewhere, [xxx setValue:something forKey:#"YYY"] is being called.
At this point, you're thinking "but I've never used setValue:forKey in my code!". You may be right. But it is used by the frameworks when you load a xib file - all the outlets are set using key-value coding.
So, you will have an outlet in your xib that is connected to something that has since been removed or renamed in the class it links to. If you're lucky, it will have a little exclamation mark next to it. If you're not, you won't even see it in interface builder and you'll have to edit the xib as source code and remove it from the XML.
You are calling setValue:forKey: method somewhere (probably, on a NSMutableDictionary where you should call setObject:forKey) or something similar...