iphone - How to send a message from one object to another? - iphone

I'm kind of a newbie to objective programming, so sorry for the dumb question.
I'm doing some kind of a messenger for some social network, and i'm stuck at the very simple thing - how to send a message from the object of one class to the object of the another class?
I have a class, called SignInViewController, which creates an instance of SignUpViewController after a SignUpButton is pressed and it's done just like that:
SignUpViewController *signUpViewController = [[SignUpViewController alloc]init];
signUpViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:signUpViewController animated:YES];
Then, after some management done with the AFNetwork (i use a specific class for this, called ServerManager), i want to send the message to draw a new textfield in my SignUpViewController instance, and i think it could be done like that:
in the SignUpViewController.h:
- (void)showTheCodeTextField;
in the ServerManager.m:
[[SignUpViewController self] showTheCodeTextField];
and then in SignUpViewController.m:
-(void)showTheCodeTextField
{
NSLog(#"Time to draw codeTextField");
}
I am getting a familiar SIGABRT at the latter line of code. I know I am doing something wrong, but I just can't figure out what exactly.
Could you help me out please?

You can use NSNotificationCenter to make that work.
After presenting your SignUpController you add it as an observer of notifications that ServerManager sends.And when that notification comes, you call your message to draw the view.
So, after
SignUpViewController *signUpViewController = [[SignUpViewController alloc]init];
signUpViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:signUpViewController animated:YES];
Make an observer
[[NSNotificationCenter defaultCenter]signUpViewController selector:#selector(showTheCodeTextField:) name:#"SignUpSucceded" object:[ServerManager sharedInstance]];
Than, in your Server Manager, you send a notification, containig that textField, and the method in your SignUp gets called.That's it.You've got the textField text in your notification.userinfo
[[NSNotificationCenter defaultCenter]postNotificationName:#"SignUpSucceded" object:self userInfo:[NSDictionary dictionaryWithObject:textField.text forKey:#"login"]];
}
Getting tour Text here in signUpView
-(void)showTheCodeTextField:(NSNotification*)notification
{
NSLog(#"Time to draw codeTextField %#",[notification userInfo]);
}

it is better if you use delegate on button event declare your delegate where you create your button and just use that delegate in any class where ever you want just use that delegate it is very helpful learn delegate for objective c its easy and efficient

Your ServerManager class needs to have a reference to the SignUpViewController instance. Right now you are getting the self of the class not of the class instance. You should probably have a property on your ServerManager class which references the instance of your SignUpViewController.

Looks like you're trying to send a message to a class (SignUpViewController) instead to it's instance/the object (signUpViewController):
Change
[[SignUpViewController self] showTheCodeTextField];
to
[[signUpViewController self] showTheCodeTextField];
and you should be o.k.

If you have an instance of SignUpViewController in your ServerManager instance, you'd use this convention (assuming your instance is named 'signUpController'):
[[self signUpController] showTheCodeTextField];
Another possibility would be to send your ServerManager a notification containing a reference to your SignUpViewController, and passing the showTheCodeTextField message to that. This assumes you have knowledge of how to send a notification.
Good luck to you in your endeavors. You look like you're just getting started in Cocoa and Objective-C. Hang in there!

Related

Getting another controllers instance class

I have learned how to pass and instance of a class to another class, but I have yet to understand how to do it the other way arround.
Example:
Lets say that we are in rootViewController and in the didSelectRowAtIndexPath we pass the instance of playlist to someviewcontroller like this:
SomeViewController *someViewController = [[SomeViewController alloc] initWithNibName:nil bundle:nil];
playlist = [arr objectAtIndex:indexPath.row];
someViewController.playlist = playlist;
Now this works perfectly for passing the class instance forward, but lets instead say that Im in the someViewController and want rootViewController playlist.
How would I go about achieving this using a similar technique? Thanks for helping!
You should check out the delegation pattern: https://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html
Also check out Apple's CoreDataRecipes sample code:
http://developer.apple.com/library/ios/#samplecode/iPhoneCoreDataRecipes/Listings/ReadMe_txt.html
You can see in the sample code that the RecipeListTableViewController is a delegate of the RecipeAddViewController so that when the RecipeAddViewController is done RecipeListTableViewController can show the recipe in the RecipeDetailViewController.
Delegation also helps with your object graph because the reference to the delegate is a weak link which means that it won't retain your delegate. So by using the delegation pattern you ensure that you don't create any retain cycles and ARC will take care of memory management for you.

can't able to handle UIActions from subclasses

I am creating a class for soap webservice to get some information from .net webserver.
for that i am using NSMutableURLRequest and parse the result using NSXmlParser.
Now i am calling that web services class from myviewcontroller.m class like this.
mywebserviceClass *obj=[[mywebserviceClass alloc] init];
[obj mymethod];
i am adding result to an array to use that array details in myviewcontroller.m class.
but i did n't get details into array while i am using that array immediately after this method.
i am trying like this by calling another method after 2 sec to use that array like this.
[self performSelector:#selector(myanotherMethod) withObject:nil afterDelay:2];
i know the reason why it is, it takes time to parse.
I am trying another way like i am creating object for viewcontroller and call this method like this.
myviewcontroller *obj=[[myviewcontroller alloc] init];
[obj myanothermethod];
NOw i can able to get details but i can't able to handle UIActivities like raising alerts.
While as told in the above performSelector method i can able to handle all UIActivities.
But i need to call that method after completion of parsing of result.
Can any one please help me.
Thank you.
Call your web service in viewDidLoad/ViewWillAppear methods of UIViewController. Collect your data and then call Parse method like- [self performSelectorOnMainThread:#selector(methodName) waitUntilDone:YES]; Below that use your array to display view or if you are displaying in table view then just call [mytblviewobj reloadData];

Button Touch Only Works Once

For some reason, interaction with my UIButton only works once. I've tried both via IBAction, and by IBOutlet with "addTarget". I have no idea why.
Context:
BaseViewController
- (IBAction) button_touched:(id)sender; //<-- Declared here, but not implemented
- (void)userInputReceived:(BOOL)bSuccess; //<-- Declared here, but not implemented
ViewController1 : BaseViewController
- (IBAction) button_touched:(id)sender; //<-- Implemented here
- (void)userInputReceived:(BOOL)bSuccess; //<-- Implemented here
Also, this is where I try "addTarget" but that doesn't work either (first touch works, but not the second)
In the "button_touched" method of ViewController1 (vc1), I make a call to another class like this:
[someOtherClassObject doSomethingWithMyView:self];
That class simply pops up a message box, gets user input, then calls back on the viewcontroller:
(Inside SomeOtherClass):
-(void)doSomethingWithMyView:(BaseViewController*)vc
{
// Do Something
[vc userInputReceived:TRUE];
}
Once this workflow has executed once, the button touch never calls the "button_touch" method again. No matter what I do, I can't get this to be called again.
In a thread on one of the popular BBS forums, someone mentioned that a problem like this could be caused by not having the object (vc1) you think you do, but rather, another instance of it. So, I logged the instance like NSLog( "instance: %p", self) in numerous places, and it's always the same.
Any ideas are greatly appreciated. This is very frustrating.
shot in the dark maybe, but its possible that your view controller's view has lost first responder status due to the displaying of the message inside the other object (what type of object is this and how is the message displayed?).
Try after your statement:
[vc userInputReceived:TRUE];
adding the line
[[UIApplication sharedApplication].keyWindow makeFirstResponder:vc.view];

Reloading A View iPhone

So I have two views A and B. A is a profile view, B is a login view. A loads B in the ViewDidLoad Method using
LoginViewController *lvc = [[LoginViewController alloc]initWithNibName:#"LoginViewController" bundle:[NSBundle mainBundle]]; //make new instance of LoginViewController
[self presentModalViewController:lvc animated:NO]; //present the LoginViewController
[lvc release];
in the login View, if the login is successful, the view is removed
[self dismissModalViewControllerAnimated:YES];
On the login view, It downloads some data which I want to display on the profile view. How would I go about sending the data to the profile view and displaying it in the xib. I believe the profile view is already displayed but is just hidden.
This is a basic "communicate between two classes" question. There are many ways to do this, but here are three. I only wrote sample code for delegation (because I think that's probably the best choice in your situation), but let me know if you want examples of notifications or KVO.
Delegation Implement a delegation or callback method in Class A. Delegation is best for small class hierarchies. If Class A is the only class that will load B and A is the only class who cares what happens in B, then delegation is the easiest way to move data around. It's simple to implement, it's simple to understand and there's a clear relationship between the classes.
// Class A
- (void)displayLoginViewController {
LoginViewController *lvc = [[LoginViewController alloc]initWithNibName:#"LoginViewController" bundle:[NSBundle mainBundle]];
lvc.delegate = self;
[self presentModalViewController:lvc animated:NO]; //present the LoginViewController
[lvc release];
}
- (void)loginViewControllerWasSuccessfull:(LoginViewController *)loginViewController {
// Do whatever you need to do here
[self dismissModalViewControllerAnimated:YES];
}
In the login view controller do something like this in the header:
#property (assign) NSObject delegate; // declared assign so you don't have circular references
… and this in the implementation:
- (void)didLogin {
[self.delegate loginViewControllerWasSuccessfull:self];
}
Notification Class A will register to listen for login notifications. Class B will post login notifications. Notifications are best if the classes that care about login are distributed. i.e. there are many classes that care about a login event and they may not necessarily have a direct relationship with the class that is performing the login.
Key Value Observing KVO is best if you don't particularly care about the login event, you care about the changes to the data. You will have some class that manages your data, probably an NSManagedObject if you are using Core Data. Class A will observe changes to whatever property it's interested in. Your LoginViewController will update that data class when it is finished downloading data. Class A will be notified that the data has changed.
Whatever solution you decide to use, the choice ultimately comes down to asking, "What does Class A care about?". Does Class A need to know that Class B successfully logged in? Use delegation. Does Class A need to know that somewhere, some class logged in? Use notifications. Does Class A not care about logins, it only needs to know if data has changed? Use KVO.
You Load view A after downloading the data instead of ViewDidLoad.
when u click on the login button then download data and display it.
if your viewWillAppear is not calling then create nsnotification center object and post it when you want to call your view willAppear method.and then remove this notification.
you can store the downloaded data at delegate file in login view. And in viewWillAppear method of profile view use data from the delegate....
for that you have to create variable and set its property in .h and .m file .than you can set this variable value in login screen and it will synthesize to profile screen.
Another way
you have to create variable in appDalegate . appDalegate value set in login screen and use this value in profile screen
If I understand correctly, you are trying to do the equivalent of Android's Intents. Therefore I advise using iOS's NSNotificationCenter and send NSNotifications with associated data.

iPhone: Access a class from another class

I want to make a program that parses an XML file and then updates labels on 2 different tab bar views. On both of these views, I have a refresh button to update the results. What I'd like to do is update both of the views labels from either view. I figure the AppDelegate is probably a good choice to make this happen, but I tried creating classes that the AppDelegate can access but since they're instances of a class they contain no values. I get no errors but the labels don't update even though the data changes. This is the method in my AppDelegate that is called after the XML is parsed:
-(void)callUpdateValues {
NSLog(#"Calling Update from AppDelegate");
home *homeController;
data *dataController;
[homeController updateValues];
[dataController updateValues];
}
One of the update methods looks like:
- (void)updateValues {
NSLog(#"Call Home");
[label1 setText: [[[[totalData objectAtIndex:0] objectForKey:#"nodeChildArray"] objectAtIndex:7] valueForKey:#"nodeContent"]];
[label2 setText:[[[[totalData objectAtIndex:0] objectForKey:#"nodeChildArray"] objectAtIndex:1] valueForKey:#"nodeContent"]];
}
So the view calls the AppDelegate method "callUpdateValues" and then that method should call the individual "updateValues" methods in each view. I am not an expert on this by any means, and I'm really just trying to get an idea of how programming on the iPhone works. I'm probably just not understanding something here, and if someone could give me some sort of answer I'd appreciate it.
Cocoa has a number of classes available for notifying interested parties of changes. Directly calling methods as you describe makes things much more closely coupled than you need to.
In your method that generates the update you'd have:
[[NSNotificationCenter defaultCenter] postNotificationName:#"IGotSomeNewData"
object:newData
userInfo:nil];
And in the classes that want to hear about updates you'd register for the notification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(newStuff:)
name:#"IGotSomeNewData" object:nil];
And then implement the method that gets called when something happens:
- (void) newStuff: (NSNotification *)notification {
id newData = [notification object];
// Do stuff
}
There's some really great stuff getting done by Apple for XML on the iPhone: XML Reading Material
The first snippet is out of place. I think what you're missing is that you need to create your instances within the AppDelegate.h, expose them using properties (and synthesizing them in the .m). Then you're update structure should fit better.
If you're just picking up iPhone programming, start digging into the guides that apple provides, and even if you're not into that, start pulling down at least 5 sample code projects a day. The beauty of them is that you can build them (even onto your iphone) and if you like a feature, you can see how it's done. Alternatively, get the grapefruit book from APRESS. Beginning iPhone.
Hope this helped.
In the example you gave, homeController and dataController are not properly initialized. If I understand your project correctly, you would have created instances of the homeController and dataController classes in your main XIB file, and connected them up to the appropriate views (label1 and label2). Your AppDelegate should, then, look something like this:
...
#class homeController;
#class dataController;
#interface AppDelegate
{
IBOutlet homeController * home;
IBOutlet dataController * data;
}
...
#end
With this in place, you would add (in your application XIB file), links from your homeController and dataController instances to the appropriate outlets (labeled home and data) in your application delegate.
Then, you could simply reference them by name in your callUpdateValues method:
-(void)callUpdateValues {
NSLog(#"Calling Update from AppDelegate");
[home updateValues];
[data updateValues];
}
On a side note, Cocoa coding standards usually specify that class names are capitalized. This is, of course, up to your personal taste, but if you're just getting started in Cocoa, it may be worth drinking one more cup of kool-aid at this point, just so your code will "fit in" with what most other developers are doing. Again, totally up to you!