Description of the problem is shown below:
Function contained in the UIViewController link functions contained in the NSObject
NSObject return value to another function contained in UIViewController
When a function referenced to UIViewController it does not update UILabel
UILabel found in UIViewController
NSObject class:
-(void)getCategoryId:(NSString *)categoryid {
categoryMap *catMap = [[categoryMap alloc] init];
[catMap getCategoryId:categoryid];
catMap.nePOI = categoryid;
}
UIViewController:
-(void)getCategoryId:(NSString *)categoryid {
self.label.text = categoryid;
}
You are creating an new categoryMap View controler object and you are updating its label, not the one from the categoryMap view controller that is being currently displayed.
To achieve what you want, the "NSObject" instance would have to have a refen-rence (property) pointing to the ViewController that is actually displayed on screen.
-(void)getCategoryId:(NSString *)categoryid {
// View controller is created
categoryMap *catMap = [[categoryMap alloc] init];
// label updated
[catMap getCategoryId:categoryid];
catMap.nePOI = categoryid;
// End of the method, View controller is destroyed
// See the problem here??? You are not updated the good viewController...
}
Although this is not a recommended way to go. Your viewController should ask the object what to display, not the other way around. But, in your case, you can fix this with a notification. Replace the implementation of getCategoryId: in the object class by
[[NSNotificationCenter defaultCenter] postNotificationWithName:#"categorySelected" object:categoryId];
and subscribe to it in your view controler viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(getCategoryId:) name:#"categorySelected" object:nil];
and then replace the getCategoryId: method of your view controller by:
-(void)getCategoryId:(NSNotification *)notif {
self.label.text = (NSString *)(notif.object);
}
That should do... ;)
To better understand architecture behind the ViewController principles, please refer to Apple MVC documentation: https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
Related
I want to update the view controller that is covered with a modal view in my application, I'm using swift. What I have currently is this:
The view on the right is the caller, and the views on the left are the modal views triggered by each button from the first one. They do basic edit, add new operations. These views are modally presented over the main one, and what I want to do is update the table view controllers enbedded in the two containers once I save the data from one of the modals.
I researched the use of one of the viewLoad events, but I'm kinda stuck at the moment. How can I do this?
Well you can do it in two ways
1. Delegate
2. NSNotificationCenter
In your Model class.h file
#protocol someProtoColName<NSObject>
-(void)finishedDoingMyStuff;
#end
#interface ModelClass()
#property (nonatomic,weak) id<someProtoColName> delegateObj;
Then in your ModelClass.m
-(void)someactionHappend{
//this is the method where you save your things call the delegate method inside here like this.
[self.delegateObj finishedDoingMyStuff];
}
Then in your CallerClass.h
#import ModelClass.h
#interface CallerClass:UIViewController<someProtoColName>
Inside CallerClass.m viewDidLoad
-(void)viewDidLoad{
ModelClass *model = [[ModelClass alloc]init];
model.delegateObj = self;
}
//Now declare the delegate method
-(void)finishedDoingMyStuff{
//update your code that this has happend. this will be called when your model class's button action inside which you sent the `self.delegateObj`message is invoked instantaneously.
}
NSNotificationCenter
CallerClass.m
-(void)viewDidLoad{
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(someMethod) name:#"NOTIFICATIONNAME" object:nil];
}
-(void)dealloc{
[[NSNotificationCenter defaultCenter]removeObserver:self name:#"NOTIFICATIONNAME" object:nil];
}
-(void)someMethod{
//something has happened, do your stuff
}
And in each of the Model class (if they are many or one dsnt matter)|
ModelClass.m
-(void)someactionHappend{
//this is your action method that you want to do stuff in the model
[[NSNotificationCenter defaultCenter] postNotificationName:#"NOTIFICATIONNAME" object:nil userInfo:nil];
}
Hope this helps you out.
I am very new to iOS and overwhelmed with resources I find online. My use case is simple
a.) ViewController parent has label called categoryLabel. A tap on label category opens a new view View 1
b.) View 1, shows all groups. Lets says A, B, C. This will be shown on table
c.) when user click on any group A, B or C, a new view View 2 appears with all categories in that group. For example, user clicks on A and on View 2 user sees categories A1, A2, A3.
d.) Now when user clicks on any specific category, how does that goes back to ViewController parent and assigns to categoryLabel?
I do not know what is the best way to approach this design.
Any guidance is very much appreciated
hope this will help
let take an example , your are going from A -> B and want send some data from B to A , there are many technique to do that but using delegate method and block are nicer way.
delegate way :-
in your B.h file
#protocol yourDelegate <NSObject>
-(void)whichCategoryClicked:(NSString *)categoryName;
#end
#interface B : UIView
#property(nonatomic, assign)id<yourDelegate> delegate;
in your B.m
just call this delegate method after Clicking particular category.
[self.delegate whichCategoryClicked :#"Category_name"];
in your A.h
assign it as delegate and import the above class
#interface A.h : UIViewController<yourDelegate>
and in Implement this method in A.m
first in your viewdidload
{
B *objB = [[B alloc]init];
objB.delegate = self;
}
-(void)whichCategoryClicked:(NSString *)categoryName
{
categoryLabel.text = categoryName;
}
You can use Local notification for this purpose names as NSNotificationCenter in iOS. Which works as follows:
To send a notification that is from the view on which you are and want to send some value from that view, use below code:
NSDictionary *dict;
[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationKey" object:nil userInfo:dict];
and now on any of the view controller, you can add observer on viewDidLoad of that class as:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(methodToCall:)
name:#"NotificationKey"
object:nil];
Now call method written in above line:
- (void)updateImageFromArray:(NSNotification *)notification {
// your dict
NSDictionary *dictUserInfo = [notification userInfo];
}
I have a function called sendDataToMotor. It is in my First View Controller classes. I have another view controller called SecondViewController. I need to call this function from the Second View Controller.m class. I tried declaring the property:
#property(nonatomic,assign)UIViewController* firstController;
in my SecondViewController.h class. Furthermore, I wrote the code bellow in the viewDidLoad part of my SecondViewController.m class (where I want the function to be called).
secondViewController = [[SecondViewController alloc] initWithNibName:#"secondViewController" bundle:nil];
secondViewController.firstController = self;
[self.firstController performSelector:#selector(sendDataToMotor)];
But, Im getting an error with the first word in that code (secondViewController) because of an undeclared identifier issue. Furthermore, I get an error with the second line (secondViewController.firstController = self) because secondViewController has an unknown name type.
In summary, I don't care if you use the above code to answer my question: that was just something I tried to implement that I found online. However, I'm looking for the simplest way to call a function from another View Controller.
Notification Center could be solution to you question.
Receiver UIViewController
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification:)
name:#"myNotification"
object:nil];
}
- (void)receiveNotification:(NSNotification *)notification
{
if ([[notification name] isEqualToString:#"myNotification"]) {
//doSomething here.
}
}
Sender UIViewController
- (void)sendNotification {
[[NSNotificationCenter defaultCenter] postNotificationName:#"myNotification" object:self];
}
You want to use the delegate pattern, and you are almost there.
This line in secondVC:
#property(nonatomic,assign)UIViewController* firstController;
should be generalised so as not refer to a specific type
#property(nonatomic,weak)id <delegateProtocol> delegate;
And you should accompany that with a protocol declaration in the header of your secondVC (above the #interface declaration), something like
#protocol SecondVCDelegate
- (void) sendDataToMotor;
#end
In firstVC interface you can declare your adherence to the delegate protocol in the first line of the #interface declaration in the header file
#interface firstVC < SecondVCDelegate >
Or in the first line of a private interface declaration in the .m file
#interface firstVC() < SecondVCDelegate >
Then you won't need to use performSelector (which anyway should be preceded by a safety check) as the compiler will alert you of errors.
In firstVC after creating secondVC, set it's delegate property to self(i.e. firstVC)
secondVC.delegate = self;
then in secondVC you can just call the method directly on it's delegate:
[self.delegate sendDataToMotor];
I explain this in more (wordy) detail here...
https://stackoverflow.com/a/14910469/1375695
There are many problems in your code. I'm going to assume the second chunk of code you included is actually in -viewDidLoad in FirstViewController not the second.
The error you're getting is because you aren't putting the type before secondViewController. It should be SecondViewController *secondViewController = ...
This probably still won't work for you because when you perform your transition to the second view controller, you won't be using the same object.
I created a singleton in ios7 like this:
SharedData.h
#interface SharedData : NSObject
{
}
+ (id)sharedInstance;
#property (strong, nonatomic) NSMutableArray *list;
#end
SharedData.m
#import "SharedData.h"
#implementation SharedData
#synthesize list;
// Get the shared instance thread safe
+ (SharedData *)sharedInstance {
static dispatch_once_t once = 0;
static SharedData *sharedInstance = nil;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init {
self = [super init];
if (self) {
//initialize
list = [[NSMutableArray alloc] init];
}
return self;
}
#end
I always use this code to access this class:
SharedData *sharedData = [SharedData sharedInstance];
The problem is now when I switch the view in my viewDidLoad method the list is empty but in my viewDidAppear method everything is fine. Any ideas?
EDIT:
This is the code how I change the views:
SharedData *sharedData = [SharedData sharedInstance];
//clear feed and add new feed
[sharedData.list removeAllObjects];
[sharedData.list addObjectsFromArray:newList];
//show new gui
[self.navigationController performSegueWithIdentifier:#"goToMain" sender:self];
NOTE: I push from a normal ViewController to a TabBarController -> NavigationController -> TableViewController to display the list.
I guess you have the confusion between these two viewcontroller methods:
-(void)viewDidLoad{
//
}
&
-(void) viewDidAppear{
//
}
viewDidAppear is the method which is called each time your view changes but viewDidLoad is the method which is not necessarily called each time your view changes.
ViewDidLoad method is called when view loads for the first time, after that it doesn't get called until the views are removed/released.
P.S: I suggest you to put the breakpoint in your viewDidLoad and viewDidAppear method and feel it. Your answer lies there.
Hope this helps you alot.
Good Luck.
The problem was i created a segue which went from the button to the next view. Because of this the viewDidLoad gets earlier called than the list assigned. I just changed the segue to go from view to view.
How are you changing from one viewController to the other? Wich classes are the parents of your destination ViewController?,
If you are modifying properties of the view in the prepareForSegue method... you are forcing the view to load.
For example, you are setting the list of your singleton in prepareForSegue, but before setting the list you are modifying a property of your destination viewController. (doing something like destVC.view = XXX or destVC.viewControllers = XX if you are subclassing a UITabBarViewController...) Then you are triggering the viewDidLoad method , and it's executing before you have set the list to the correct value.
Or maybe you are seguing in two different places to the destinationViewController. And when the viewDidLoad happens, you still have not updated the list on the singleton.
Here is the transcription of the chat with the poster of the question: https://chat.stackoverflow.com/transcript/55218
I know this question is asked once every two days. I can not see what I am doing wrong though.
I have a storyboard navigation controller based app.
My notification and pop / push segues works well, only thing is I can not add string to parents view NSmutablearray.
I want to add a string object to parent view's nsmutablearray. My decent code does not pass any data.
parent.h
#interface CreaatePlistTableViewController : UITableViewController<UITableViewDelegate, UITableViewDataSource>{
NSMutableArray *presenterList;
}
#property (nonatomic, strong) NSMutableArray *presenterList;
parent.m
NSString * const NOTIF_CreatePlist_UpdateTableview= #"CreatePlist/UpdateTableview";
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Private interface definitions for update tableview
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#interface CreaatePlistTableViewController (private)
- (void)CreatePlistUpdateTableview:(NSNotification *)notif;
#end
#implementation CreaatePlistTableViewController
#synthesize presenterList=_presenterList;
- (void)viewDidLoad
{
[super viewDidLoad];
_presenterList=[[NSMutableArray alloc] init];
// Register observer to be called when logging out
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(CreatePlistUpdateTableview:)
name:NOTIF_CreatePlist_UpdateTableview object:nil];
NSLog(#"Presenter List: %#", _presenterList);
}
- (void)CreatePlistUpdateTableview:(NSNotification *)notif{
NSLog(#"Notification recieved");
NSLog(#"Presenter List: %#", _presenterList);
[_createPlistTableview reloadData];
}
child.h
#interface AddPresenterViewController : UITableViewController<UITextFieldDelegate,UIAlertViewDelegate>{
CreaatePlistTableViewController *crereaatePlistTableViewController;
}
#property(nonatomic,strong) CreaatePlistTableViewController *crereaatePlistTableViewController;
child.m
#synthesize crereaatePlistTableViewController=_crereaatePlistTableViewController;
//finished adding presenter
-(IBAction)finishedAddingPresenter:(id)sender{
//some xml string here
NSLog(#"final result XML:\n%#", writer.XMLString);
_crereaatePlistTableViewController=[[CreaatePlistTableViewController alloc]init];
//add object to parents view data source
[_crereaatePlistTableViewController.presenterList addObject:writer.XMLString];
//dismiss the view
[self.navigationController popViewControllerAnimated:YES];
//notify the parent view to update its tableview
[[NSNotificationCenter defaultCenter] postNotificationName:#"CreatePlist/UpdateTableview" object:nil];
}
Output
Notification recieved
Presenter List: (
)
So notification works when I click the button. But it does not pass object to nsmutablearray.
What I am doing wrong here ? How can I add an object to parent view's nsmutablearray?
It seems everything is good except your alloc of parent view object I am not that familiar with storyboard but You said you are using navigation navigation controller
so change this
_crereaatePlistTableViewController=[[CreaatePlistTableViewController alloc]init];
to
_crereaatePlistTableViewController= [self.navigationController.viewControllers objectAtIndex:0];
It may work I am not sure
You wrote this.
[_crereaatePlistTableViewController.presenterList addObject:writer.XMLString];
Do you ever initialize the array? No. Use the debugger and you will see that at this line the presenterList is nil.
Now as a point of style. Avoid using NSNotificationCenter to pass data or signaling other objects. #TheRonin gave a handy link. You should also look into some tutorials on Segues, because these are solved problems.
This is another related post that you might find interesting.