How to back to UIViewController from a NSObject Class in iOS - ios

I have a UIViewController Class. In that class I implement a UIWebView. On that WebView I got data from CocoaHttpServer and loading a html page. In CocoaHTTPServer have a NSObject Class. In that Class I got one method for pop to previous Screen. How to Pop to view controller from NSObject class.
This is my NSObject class
if([[array lastObject] compare:#"back-button-clicked"] == NSOrderedSame) {
[self handleBackActionRequest];
}
-(void)handleBackActionRequest
{
PGSoftApViewController *softAP = [[PGSoftApViewController alloc] initWithNibName:nil bundle:nil];
[softAP webToBackNativeCall];
}
This is in my ViewController class :
-(void)webToBackNativeCall
{
[self.navigationController popViewControllerAnimated:YES];
}
This is not working. I am able to insert webToBackNativeCall method. But its not happening anything.
I have to go back. How can I. Please help me.

In your NSObject.h class add protocol like this
#protocol nsobjectDelegate <NSObject>
-(void)navigateToBackVC;
#end
#interface objectClass:NSObject
//your other code
#property (nonatomic,weak) id<nsobjectDelegate> objDelegate;
#end
In you NSObject .m class
-(void)webToBackNativeCall
{
// this method you already have
// other code if you want
[self.objDelegate navigateToBackVC];
}
In you view controller .h class
#interface objectClass:NSViewcontroller <nsobjectDelegate> // delegate of NSObject include it in VC when you want to call that methods
In you view controller .m file in viewDidLoad or willAppear or DidAppear method initializ object of NSObject class and set delegate
NSObjectClass *objeObject = [[NSObjectClass alloc] init];
objeObject.objDelegate = self;
implement this method
-(void)navigateToBackVC
{
[self.navigationController popViewControllerAnimated:YES];
}
This is general concept of protocol and delegate.
Hope this might help you.

In viewDidLoad of your ViewController
[[myNSOBjectClass alloc] startViewController:self];
In NSObject Class
#interface myNSOBjectClass{
//Global access to the view controller.
UIViewController *viewController;
}
#implementation myNSOBjectClass
//function that the caller calls to pass their UIViewController
- (void)startViewController:(UIViewController *)callerViewController{
viewController = [[UIViewController alloc]init];
//puts the caller's view controller to the global member.
viewController = callerViewController;
}

Related

Interact with Parent view controller when selecting a table cell in a container view

I have this problem that I want to hide the container view from the parent VC when I tap a table cell at the last VC on the right.
I tried hooking up a protocol delegate but it did not work.
Here is my failed attempt:
I added the Protocol on the GOCategoryMenuViewController.
#protocol GOCategoryMenuViewControllerDelegate <NSObject>
-(void)hideMenu;
#end
#interface GOCategoryMenuViewController : UIViewController
#property(weak, nonatomic) id <GOCategoryMenuViewControllerDelegate> delegate;
#end
Implement hideMenu in the .m file
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate hideMenu];
}
Import the header and delegate to the parentVC
#import "GOCategoryMenuViewController.h"
#interface ViewController : UIViewController<GOCategoryMenuViewControllerDelegate>
Implement the hideMenu in the .m of ParentVC
-(void)hideMenu
{
NSLog(#"Hide the menu");
}
I believe I need to also declare self on the delegate, but I don't know how and I tried searching for a solution on the web to no avail. It's why I'm asking directly now to you all. Please help and thanks!
Your protocols is true, only thing you have to do is when you init instance of GOCategoryMenuViewController you should give it a delegate sth like this:
GOCategoryMenuViewController *category = [[GOCategoryMenuViewController alloc] init];
//if you don't give delegate, never your delegate method will get called
category.delegate = self;
You have to delegate your instance of GOCategoryMenuViewController class.
If you want to solve it with delegates only, then you must pass the parent view controllers controls delegates to the child view controllers with declaring the properties that has the same type with the parent control in the child view controller. Then you can do any operation on the parent view's control in the child view controller.
ParentViewController.h class
#interface ParentViewController : UIViewController
{
NSMutableDictionary *dictOfPeople;
}
#property(nonatomic, retain) NSMutableDictionary *dictOfPeople;
ParentViewController.m class
#synthesize dictOfPeople;
- (void)anyMethod
{
//initialize child view controller
ChildViewController *childViewController = [[ChildViewController alloc] init];
// here is important
childViewController.owner = self;
}
ChildViewController.h class
#interface ChildViewController : UIViewController
{
id owner;
}
#property(nonatomic, assign) id owner;
ChildViewController.m class
#synthesize owner;
- (void)anyMethod
{
// You can access parent view controllers dictOfPeople dictionary like this
int totalNum = [((ParentViewController *)self.owner).dictOfPeople count];
//...
}

how to send data back with dismissViewController

i have 2 views in iPhone application. FirstViewController and MultiSelectViewController.
in FirstViewController there is a button to go to MultiSelectViewController. In MultiSelectViewController i have a tableviewcontroller to multiselect and send result back to FirstViewController with Done button
my problem is with done button. i don't know how to send data back to the FirstViewController. it has to be with dissmissviewcontroller.
this is .h file of MultiSelectViewController
#protocol MultiSelectDelegate <NSObject>
-(void) multiselectViewControllerDismissed;
#end
#interface MultiSelectViewController : UITableViewController
{
__weak id myDelegate;
}
#property(nonatomic,retain)NSArray *myData;
#property(nonatomic, retain)NSMutableArray *selectedData;
#property (nonatomic, weak) id<MultiSelectDelegate> myDelegate;
this is my done button in .m file of MultiSelectViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.allowsMultipleSelection = YES;
selectedData=[[NSMutableArray alloc] init];
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(multiselectViewControllerDismissed)];
self.navigationItem.rightBarButtonItem = barButton;
}
and lastly here is my done button action:
-(void)multiselectViewControllerDismissed
{
NSLog(#"%#",selectedData);
}
i don't understand how can i send data and get back in FirstViewController
You redefine
multiselectViewControllerDismissed delegate method as
multiselectViewControllerDismissedWithData:(NSMutableArray *)dataSelected
And, in .h file of FirstViewController implement the delegate i.e.,
#interface FirstViewController: UIViewController <MultiSelectDelegate>
and in the button action of FirstViewController.m assign delegate of MultipleSelectViewController as self. ie.,
MultipleSelectViewController * msvc = [[MultipleSelectViewController alloc] init];
msvc.myDelegate = self;
and implement
-(void)multiselectViewControllerDismissedWithData:(NSMutableArray *)dataSelected
this method in FirstViewController.m
And, in the Done button action method of MultipleSelectViewController.m, call method multiselectViewControllerDismissedWithData with delegate i.e.,
[self.myDelegate multiselectViewControllerDismissedWithData:selectedData];
That's it.
You could now pass selectedData array from MultipleSelectViewController to FirstViewController
Two standard ways of passing data in obj-c:
Use references and assign manually. In your example, the first view controller passes a reference of itself to the second view controller. The second view controller assigns a designated property with the required data using the reference.
The publisher-subscriber pattern using LocalNotifications. The first view controller listens for a particular location notification, and the second view controller, before being dismissed, does a broadcast with the data.
I'd recommend the 1st approach for your example. Some sample code:
In the .h file:
#interface FirstViewController:UIViewController
#property NSMutableArray *receivedData; //property to receive selected data
#end
In the .m file:
MultiSelectViewController *msvc = [MultiSelectViewController alloc] init];
msvc.presentingViewController = self; // pass reference of 1st VC to 2nd VC
[self presentViewController:msvc animated:YES];
In MultiSelectViewController.h file:
#import "FirstViewController.h"
#interface MultiSelectViewController: UITableViewController
...
#property FirstViewController *presentingViewController;
...
#end
In MultiSelectViewController.m file:
-(void)multiselectViewControllerDismissed
{
NSLog(#"%#",selectedData);
presentingViewController.receivedData = selectedData;
}
first create your delegate method as
-(void)dismiss:(NSString *)str;
while did select get a value from based on indexpath.row
and store it as nsstring.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.valueString=[NSString stringWithFormat:#"%#",[self.arrayValue objectAtIndex:indexPath.row]];
NSLog(#"%d",indexPath.row);
}
done button click:
call your delegate method like
[self. myDelegate dismiss:"your string which you get from table"]
[[self navigationController] popViewControllerAnimated:YES];
and in your first view controller…
import the view controller class and call delegate method..
create instance for second view controller...
MultiSelectViewController *txtNext=[[MultiSelectViewController alloc]init];
txtNext. myDelegate =self;
then
-(void)dismiss:(NSString *)str
{
NSString *strng=str;
nslog("%#",strng);
}

Add objects to an NSMutableArray in my base view controller from a second view controller, ios

I have been searching all morning how to do this. I have 2 View Controllers. From the root View Controller (ViewControllerA - which is a table view controller) you can go push to the second view controller (ViewControllerB).
In the ViewControllerB, there are two fields: contacts & textBody. When the user is done they can click on "Add". This will then go back to ViewControllerA. What I am trying to do now, is for every time that process occurs, all the information from ViewControllerB the user just added goes into a cell in ViewControllerA. The user can then add as many cells as they like.
What I can't do however, is get the information across the view controllers. I have been looking all morning at using the app delegate, singletons??, protocols, sharing properties, etc! But I am still stuck.
What I want to do, but can't, is for every time the user clicks "Add" on ViewControllerB, contacts & texts are put into an array. This array is then put into another array which holds all the smaller arrays which the user has created? If you have an ideas, or links to similar/sample code or tutorials, that would be much appreciated!
Try this using the delegate method as follows
Download Sample Project with XIBs
Download Sample Project With Storyboard
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController {
NSMutableArray *dataArray;
}
- (void)passData:(NSMutableArray *)array;
#end
ParentViewController.m
#import "ParentViewController.h"
#import "ChildViewController.h"
#implementation ParentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Initialise the mutable array.
dataArray = [[NSMutableArray alloc] init];
}
- (IBAction)btnGoToSecondView:(id)sender {
ChildViewController *secondVC = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
secondVC.delegate = self;
[self presentViewController:secondVC animated:YES completion:nil];
}
- (void)passData:(NSMutableArray *)array {
[dataArray addObject:array];
NSLog(#"Data Passed = %#",dataArray);
}
#end
ChildViewController.h
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#class ParentViewController;
#interface ChildViewController : UIViewController {
NSMutableArray *tempArray;
}
#property (strong, nonatomic) IBOutlet UITextField *txtContact;
#property (strong, nonatomic) IBOutlet UITextField *txtTextBody;
#property(nonatomic, assign) ParentViewController *delegate;
#end
ChildViewController.m
#implementation ChildViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Initialise the mutable array.
tempArray = [[NSMutableArray alloc] init];
}
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[tempArray addObject:_txtContact.text];
[tempArray addObject:_txtTextBody.text];
[self.delegate passData:tempArray];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidUnload {
[self setTxtContact:nil];
[self setTxtTextBody:nil];
[super viewDidUnload];
}
#end
With Storyboard
If you are using storyboard then create a ParentViewController segue ChildViewController and give it a identifier in my sample it showChildView
Then use the following code to set the delegate
// Calling the segue to go to the child view and setting up the delegate.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showChildView"]) {
ChildViewController *childVC = segue.destinationViewController;
childVC.delegate = self;
}
}
Then to dismiss back to the ParentViewController use the following code (from my sample)
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[tempArray addObject:_txtContact.text];
[tempArray addObject:_txtTextBody.text];
[self.delegate passData:tempArray];
}
[self.navigationController popToRootViewControllerAnimated:YES];
}
I would recommend using a singleton instance of your NSMutableDictionary as they have bailed me out of your exact situation multiple times (including custom frameworks and UITabBarControllers). Here is an example I'm currently using to implement a singleton. This methodology is also ARC-safe as well
mySingleton.h
#import <Foundation/Foundation.h>
#interface mySingleton : NSObject {
}
+ (NSMutableDictionary *) myMutableDict;
#end
mySingleton.m
#import "mySingleton.h"
#implementation mySingleton
+ (NSMutableDictionary *)myMutableDict
{
static NSMutableDictionary *singletonInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singletonInstance = [[NSMutableDictionary alloc]init];
});
return singletonInstance;
}
#end
As long as you include mySingleton.h in all of your view controllers you can access the data via [mySingleton myMutableDict]. For example: [[mySingleton myMutableDict] setObject:myObject forKey:myKey];
Good luck!
If the information is really "global" - it has only one instance across the whole app - then you should create a singleton as DB80Buckeye suggested.
If the information is something that truly belongs to ViewController1 and you want it to be modified in ViewController2 (ie ViewController2 is really part of ViewController1, it just happens to be on another screen), then you should pass that as part of the constructor of ViewController2.
-(void)view_controller_1_that_push_view_controller_2_onto_the_stack {
ViewController2* vc2 = [[ViewController2 alloc] initWithInformation:your_information];
[self.navigationController pushViewController:vc2 animated:YES];
}
#interface ViewController2
-(id)initWithInformation:(YourInformationClass*)info;
#end
Another way is to use notifications.
There are two ways to go here. The standard pattern for doing this is delegation. You don't need a singleton. ViewControllerA manages and lists your data. ViewControllerB doesn't need to know anything about all of that data so there's no reason to expose it via a singleton, etc.
Create a delegate protocol in ViewControllerB's header file. Something like this:
#protocol ViewControllerBDelegate
- (void)addContact:(NSString *)contact withBody:(NSString *)textBody;
#end
Now, specify that ViewControllerA will implement the delegate protocol in its header:
#interface ViewControllerA : UIViewController <ViewControllerBDelegate>
Don't forget to import ViewControllerB.h at the top of ViewControllerA's header.
In ViewControllerA's implementation, implement the delegate method you specified in the protocol:
- (void)addContact:(NSString *)contact withBody:(NSString *)textBody {
[self.someArray addObject:[[SomeObject alloc] initWithContact:contact body:textBody]];
[self.tableView reloadData];
}
That's obviously just an example -- not sure how you're managing your data structure and it's probably better to insert the cell someplace that makes sense.
Declare a delegate reference in ViewControllerB's header:
#property (weak, nonatomic) id<ViewControllerBDelegate> delegate;
When you present ViewControllerB, set ViewControllerA as the delegate.
ViewControllerB *b = [[ViewControllerB alloc] init...];
b.delegate = self;
In the selector triggered by the add button in ViewControllerB, call back on the delegate before popping the view controller off the navigation stack:
[self.delegate addContact:contact withBody:text];
where contact and text are the values the user entered.
One could also use a block instead of a delegate but the principle is the same -- have the second view controller only be responsible for taking input, in your case, and pass it back to the view controller managing the data.
Alternatively for delegate suggest using the following:
ViewControllerA.h:
#property (nonatomic, strong) ViewControllerB* viewControllerB;
In ViewControllerA.m
if (!self.viewControllerB)
{
self.viewControllerB = [[ViewControllerB alloc] initWithNibName: #"ViewControllerBr" bundle: nil];
}
[self.navigationController pushViewController: self.viewControllerB
animated: YES];
...
- (void) viewWillAppear: (BOOL) animated
if (self.viewControllerB)
{
NSString* contact = self.viewControllerB.contact;
NSLog(#"%#", contact);
}
...

Need assistance regarding passing data from child to parent in UINavigationcontroller

In UINavigationController this is child controller
.h
#protocol childProtocol <NSObject>
-(void)childMethod:(NSArray*)params;
#end
#property (strong, nonatomic) id<childProtocol>childDelegate;
#property (weak, nonatomic) parentVC *pVC;
.m
if([self.childDelegate respondsToSelector:#selector(childMethod:)]) {
[self.childDelegate performSelector:#selector(childMethod:) withObject:self.arry];
}
This is my parent controller
.m
-(void)childMethod:(NSArray *)params {
// some work
}
...
childVC *cVC = [[childVC alloc]init];
cVC.pVC = self;
But childMethod: is not getting called so I searched on internet and got this post
UINavigationControllers: How to pass value to higher (parent?) controller in stack?
I tried to create a weak reference but dont know how to use to make delegate pass data from child to parent?
Try this. Check the sample project attached
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController
- (void)passData:(NSString *)strText;
#end
ParentViewController.m
- (IBAction)btnGoToSecondView:(id)sender {
ChildViewController *secondVC = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
secondVC.delegate = self;
[self presentViewController:secondVC animated:YES completion:nil];
}
- (void)passData:(NSString *)strText {
NSLog(#"Data Passed = %#",strText);
}
ChildViewController.h
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#class ParentViewController;
#interface ChildViewController : UIViewController
#property(nonatomic, assign) ParentViewController *delegate;
#end
ChildViewController.m
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[self.delegate passData:#"Hello"];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
Sample Project
This is child controller.h
#protocol childProtocol <NSObject>
-(void)childMethod:(NSArray*)params;
#end
#property (strong, nonatomic) id<childProtocol>childDelegate;
#property (weak, nonatomic) parentVC *pVC;
.m
if([self.childDelegate respondsToSelector:#selector(childMethod:)]) {
[self.childDelegate performSelector:#selector(childMethod:) withObject:self.arry];
}
This is my parent controller.h
#import <UIKit/UIKit.h>
#import "ChildController.h"
#interface perentController : UIViewController < childProtocol >
.m
- (void)childMethod:(NSArray *)params {
// some work
}
EDITED :
And Dont Forget to add childViewOBJ.childDelegate = self; at the time of create ChildViewController's object. such like,
childVC *cVC = [[childVC alloc]init];
cVC.childDelegate = self;
cVC.pVC = self;
[self presentModalViewController:cVC animated:YES];
For More information about How to create/use of Protocol.
First of all, you are not checking for the same selector as you declared in your protocol declaration so it won't respond to that. You declared the method childMethod: whereas you are checking if your childDelegate responds to myMethod: selector which does not so it won't go into the if condition.
Also the parent view controller is missing the implementation the method childMethod: in its .m. Implement that in your parent view controller or it will crash because of not finding the exact selector definition.
Since you are using a UINavigationController, the parent view controller won't be lost till the child view controller exist so the childDelegate property must not be strong unless you intend to hold onto your delegate in child view controller for some reason.

How to pass NSObject from one view controller to another

I am using iOS 5 SDK with arc. I want to pass NSObject from VC1 view controller to VC2 view controller, do modification and put back into VC1 controller. I don't want to point same nsobject from both VC1 and VC2 controllers. Whenever I am passing nsobject, it should create a copy of that nsobject and do the modification. (Do not modify actual nsobject).
I have tried below code but it crashes and giving error as
-[ImageObject mutableCopyWithZone:]: unrecognized selector sent to instance 0x1364ec20
Code:
I have NSObject as :
#interface ImageObject : NSObject
#property (copy,nonatomic) NSString *path;
#property (nonatomic, readwrite) int id;
#end
In VC1 view controller:
I am passing my nsobject to VC2 view controller as follows:
VC2ViewController *vc2 = [[VC2ViewController alloc] initWithNibName:#"VC2ViewController" bundle:nil];
vc2.imageObj = [imgObj mutableCopy];
[self.navigationController pushViewController:vc2 animated:YES];
In VC2 view controller:
VC2ViewController.h file
#import "ImageObject.h"
#interface VC2ViewController : UIViewController
#property (retain,nonatomic) ImageObject *imageObj;
#end
VC2ViewController.m file
// modifying nsobject as below
-(void)modifyObject
{
UIViewController *previousViewController = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-2];
if ([previousViewController isKindOfClass:[VC1ViewController class]])
{
VC1ViewController *parent = (VC1ViewController *) previousViewController;
if(parent != nil)
{
_imageObj.id = 2;
[parent reloadData:_imageObj];
}
parent = nil;
}
[self.navigationController popViewControllerAnimated:YES];
}
Have any idea ? How to resolve this issue?
Your ImageObject class needs to conform to the NSCopying Protocol.
This answer here explains better and shows you how the code looks like.
I also think that you need to use [imgObj copy] instead of [imgObj mutableCopy] because according to apple docs:
The NSMutableCopying protocol declares a method for providing mutable copies of an object.
Only classes that define an “immutable vs. mutable” distinction should adopt this protocol.
Classes that don’t define such a distinction should adopt NSCopying instead.

Resources