Okay so the problem I'm having in one of my functions is when users are logging in through Facebook, and my app is checking wether or not their Facebook username already exists in our app (Parse.com) database.
If so, present a view controller (which is where I'm having a problem since this is in a NSObject) if not, simply write their facebook username to parse username string. Error I get is: No known class method for selector 'presentViewController:animated:completion'
Here is my code:
PFQuery *query = [PFUser query]; //1
[query whereKey:#"username" equalTo:me.username];//2
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {//4
if (!error) {
NSLog(#"Successfully retrieved: %#", objects);
if ([objects count] > 0)
{
// LOOKING TO PRESENT VIEW CONTROLLER HERE?
// TRIED:
// [self presentViewController:[#"RegisterUsername" animated:YES completion:nil];
} else {
[[PFUser currentUser] setObject:me.username forKey:#"username"];
}
} else {
NSString *errorString = [[error userInfo] objectForKey:#"error"];
NSLog(#"Error: %#", errorString);
}
}];
and since this is inheriting from NSObject, it won't allow me to use the presentViewController. Not sure what else to do from here. :-( This view controller was going to make them set a username before continuing with our app. This code is currently in a login function in a header Comms.h (NSOBJECT) for Facebook iOS SDK
NSObject does not declare the method presentViewController:. You'll need to add a UIViewController subclass to the window and then present from that. In the completion block of your dismissViewController you should remove the parent from the window.
Alternatively you could create a delegate protocol for checking the username and then notify a UIViewController of the need to either set the username internally or present a login view.
Related
I have two ViewControllers, in the first one, there are 3 key-value pairs in each PFObject, save them to parse after clicking a button. In the second ViewController, I want to create another property and save it to the same PFObject. Here is my code:
in the first ViewController:
- (void)next
{
PFObject *thisuser = [PFObject objectWithClassName:#"User"];
thisuser[#"name"] = [PFUser currentUser].username;
thisuser[#"institution"] = institution.text;
thisuser[#"major"] = major.text;
[thisuser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (succeeded)
{
GuideViewController2 *GVC2 = [[GuideViewController2 alloc]initWithNibName:#"GuideViewController2" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:GVC2];
nav.modalPresentationStyle = UIModalPresentationFullScreen;
nav.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:nav animated:YES completion:nil];
NSLog(#"success");
}
else
{
NSLog(#"nope");
}
}];
}
and in my second view controller, the user can upload a profile photo, i want this photo to be saved in the same PFObject. So is there a way to retrieve an object using [PFUser currentUser].username property? How do i get this user object under the User class in order to add a photo key-value pair?
thx.
You can just query for the user:
PFQuery *query = [PFUser query];
[query whereKey:USERNAME_KEY equalTo:username];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error)
{
if (!error) {
//You found the user!
PFUser *queriedUser = (PFUser *)object;
}
}];
Supposing the username is actually unique! USERNAME_KEY would be your username field and username the actual username.
I am using this query to find users, it works but it just shows me the first user. I want it to show me the user with the text of an UITextField.
How can I do that ?
(I have a textfield and there I type in a name and then it should show the parsed users with the name)
PFQuery *query = [PFUser query];
NSArray *users = [query findObjects];
userQuerys.text = users[0][#"username"];
Thanks very much
This code will fetch you all the PFUsers in which username is equal to the name parameter:
- (void)searchUsersNamed:(NSString *)name withCompletion:(void (^)(NSArray *users))completionBlock {
PFQuery *query = [PFUser query];
[query whereKey:#"username" equalTo:name];
[query findObjectsInBackgroundWithBlock:^(NSArray *users, NSError *error) {
if (!error) {
// we found users with that username
// run the completion block with the users.
// making sure the completion block exists
if (completionBlock) {
completionBlock(users);
}
} else {
// log details of the failure
NSLog(#"Error: %# %#", error, [error description]);
}
}];
}
An example, if you need to update the UI with the result, for example, a table:
- (void)someMethod {
// we will grab a weak reference of self to perform
// work inside the completion block
__weak ThisViewController *weakSelf = self;
//replace ThisViewController with the correct self class
[self searchUsersNamed:#"Phillipp" withCompletion:^(NSArray *users) {
//perform non-UI related logic here.
//set the found users inside the array used by the
//tableView datasource. again, just an example.
weakSelf.users = users;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//pefrorm any UI updates only
//for example, update a table
[weakSelf.tableView reloadData];
}];
}];
}
A small note: the completionBlock here wont run if there is an error, but it will run even if no users were found, so you gotta treat that (if needed. in this example, it was not needed).
Avoid running non-UI related logic on that mainQueue method, you might lock the Main thread, and that`s bad user experience.
I am using Parse as my backend for my app. Once the user logs into their account I am trying to get the next view to say "Welcome, (First Name)" at the top. However, I cannot seem to figure out how to accomplish this even using Parse's online documents. Their site directed me here for further assistance. I have tried using their query feature, but could not figure it out. In other words, I am trying to pull the current logged in user's first name, from the database and display it once logged in.
Current code:
PFQuery *query = [PFUser query];
[query whereKey:#"firstName" equalTo:currentUser]; // find user's first name
NSArray *firstName = [query findObjects];
Previous code:
PFUser *currentUser = [PFUser currentUser];
if (currentUser) {
// do stuff with the user
Welcome.text = [NSString stringWithFormat:#"Welcome,", currentUser];
Your overcomplicating things.
You don't have to execute a query every time the view loads, instead you should put this in a plist or NSUserDefaults as not to use an API request simply to display the current users name.
However, you can do the following to the current users username :
if ([PFUser currentUser]) {
Welcome.text = [NSString stringWithFormat:#"Welcome, %#", [PFUser currentUser].username];
}
First of all you should check if you actually sign-up and/or logged into Parse with this kind of function:
[PFUser signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
}];
[PFUser logInWithUsernameInBackground:#"My username" password:#"My password" block:^(PFUser *validUser, NSError *error) {
}];
Check this link: https://parse.com/docs/ios_guide#users-signup/iOS
After you did this, whenever you you want to retrieve your user information,
[PFUser currentUser] is the right way to call some information:
Say for example you want to retrieve the objectId you can get it like this:
NSString *str = [PFUser currentUser].objectId;
Or say you want to set a custom value like this:
NSString *str = #"My custom object";
[PFUser setObject:str forKey:#"MyCustomObject"];
[PFUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
}];
Than you retrieve it like this:
NSString *str = [PFUser objectForKey:#"MyCustomObject"];
You should really check the documentation and example by Parse that are really well explained ! ;)
(Here are some tutorials/Examples by Parse: https://parse.com/tutorials)
How is the transition from your login to your main view set up? Are they both two different controllers?
If so, you should look into NSNotificationCenter...
In your MainViewController, implement
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loadObjects)
name:#"loginFinished"
object:nil];
And loadObjects will be
- (void)loadObjects
{
Welcome.text = [NSString stringWithFormat:#"Welcome %#", [[PFUser currentUser] objectForKey:"userNameField"]];
}
* You need to parse the PFUser object to access its fields. Its just a dictionary so supply it a key 'username' or whatever, and you receive a value 'myusername'. *
Then in your LoginViewController, within your [PFUser logInWithUsernameInBackground:password:block
Implement this
[PFUser logInWithUsernameInBackground:#"My username" password:#"My password" block:^(PFUser *validUser, NSError *error) {
if (!error) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"loginFinished" object:nil];
}
}];
But this is basically how you should setup your login->main flow. Learn NSNotifications, Delegation, and maybe KVO... Learning these will make you a understand how data can be passed around in the iOS/Mac environment.
Heres an analogy for all of them:
NSNotification: A teacher(NSNotification poster) announces a test to all his students(NSNotification observer), or at least the one's who are currently in class, students missing class aren't observing.
Delegate: A student finishes a test and informs the professor(delegate).
KVO: A student(KVO poster) completes a question and raises their hand where the teacher or even other students could be KVOs (key-value observers) and act on their action.
Using Storyboard I have setup an application with three tab bars. When I click on one of the tabs and have a singleton datasource class perform an action, and than immediately switch to another tab, when the singleton finishes fetching data externally it tries to send it to the current tab which causes a crash because the current tab I am on does not respond to the specific delegate method that I have implemented in the singleton delegate, and should not implement since there is no reason for that specific tab to perform that action. Here is how my delegate is currently setup.
#class DataHolder;
#protocol DataHolderControllerDelegate <NSObject>
#required
-(void)logout;
#optional
-(void)friendsQuarryDidFinishWithData;
-(void)pendingFriendsQuarryDidFinishWithData;
-(void)allUsersQuarryDidFinishWithData;
-(void)additionalFriendsFoundAndAdded;
-(void)messageQuarryFinishedWithData;
-(void)thumbnailQuaryDidFinishWithData;
-(void)sentRequestUsersFoundWithData;
#end
#interface DataHolder : NSObject;
#property (nonatomic,weak) id <DataHolderControllerDelegate>delegate;
The delegate is called within the method when data is queried.
-(void)messageQuarry{
PFQuery *messageQUery = [PFQuery queryWithClassName:#"Message"];
messageQUery.cachePolicy = kPFCachePolicyCacheThenNetwork;
[messageQUery whereKey:#"recipientIds" equalTo:[[PFUser currentUser] objectId]];
[messageQUery whereKey:#"file_type" equalTo:#"original_image.png"];
[messageQUery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error){
NSLog(#"ERROR: %#, %#", error, [error userInfo]);
}else{
messagesArray = [NSMutableArray arrayWithArray:objects];
[delegate messageQuarryFinishedWithData];
}
}];
}
Than, the view controller has a delegate method, this is the inboxViewController delegate method that is called when the delegate method above is called.
-(void)messageQuarryFinishedWithData{
self.messages = [NSMutableArray arrayWithArray:dataHolder.getMessages];
[self.tableView reloadData];
}
Remember that Delegates are meant to be intimate, meaning that its a 1-1 type relationship. It seems that what you are looking for is having a one-to-many relationship which is what NSNotificationCenter is used for. I recommend looking up the NSNotificationCenter documentation form Apple.
I have set up a few Parse users, I have a button that they can click to link to fb or twitter. I want to check if they are already linked so I can have an alertview which tells the user they are already linked.
Any thoughts?
Parse provides a set of utils for this kind of thing, one part of which is:
+ (BOOL)isLinkedWithUser:(PFUser *)user
You can use PFQuery for this:
id loggedUser = ...; // Get your facebook/twitter user info after clicking login
PFQuery *query = [PFUser query];
[query whereKey:#"email" equalTo:loggedUser[#"email"]];
[query countObjectsInBackgroundWithBlock:^(int number, NSError *error) {
if(number > 0) {
// The user already exists
} else {
// No user exists with the email
}
}];
Source: Parse.com