I have a question regarding how to pass around NSManagedObjectContext. In my app, it seems like it's my AppDelegate that handles NSManagedObjectContext, so I shouldn't create other NSManagedObjectContexts in my other ViewControllers.
So the question is...
There is any convention or smart method to do this?
Thanks.
The way I pass the NSManagedObjectContext is to simply have an iVar in each view controller you pass it to. I usually modify the initialiser to include assignment, something like this....
MyNewViewController.h
#interface MyNewViewController : UIViewController {
NSManagedObjectContext *managedObjectContext;
}
...
MyNewViewController.m
#implementation MyNewViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andContext:(NSManagedObjectContext *)ctx {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
managedObjectContext = ctx;
}
return self;
}
....
Then when you call the view controller, you simply use the modified initialiser. Like...
MyNewViewController *nv = [[MyNewViewController alloc] initWithNibName:#"MyNewViewController" bundle:nil andContext:self.managedObjectContext];
Now you've got a reference to the managedObjectContext which you can use within your view controller.
Related
Here is my problem:
I have a basic application with a UIViewController embedded in a NavigationController. It is also the RootViewController of the application. From there I have a push segue to a normal UIViewControllerand a second push segue to a UITableViewController with its own UIViewController for the detailed view.
In the root view there is an instance of the class whose purpose is to send message with a define protocol.
In the table view the user will select the type of message he wants to send and in the detail view the content of that particular type of message.
Now the user has specified everything and I want him to push a "send" button. That button must do two things: pop back to the root view and send the user defined message by the protocol class instance.
I can do the pop back just fine with:
[self.navigationController popToRootViewControllerAnimated:true];
but I have no idea how to send the message (a class instance) back to the root view. The application is still fresh so I can completely change the structure if this one is not correct.
The best for me would be to access the protocol class instance from everywhere (I will need it in the other UIViewController) but I am not sure how to do that so that's why I thought of sending the message back to the root view.
If you know how to do one of the two above please give me a hand!
Cheers.
EDIT: Technically the NavigationController is the initial ViewController so I am not really sure who is the RootViewController anymore.
First: You could do: (only works when your view has been added to a the window)
[self.view.window.rootviewcontroller doSomething];
Second option is to define a property on your appDelegate:
#property (nonatomic, strong) UIViewController *root;
And call it through:
AppDelegate *appDelegate= (YourAppDelegateClass *) [[UIApplication sharedApplication] delegate];
[appDelegate.root doSomething];
you can Create an application object and assign the message to it. and use it on your root view controller. if i understood your question correctly this might help.
You could try:
UIApplication *myApp = [UIApplication sharedApplication];
UIWindow *frontWindow = [myApp.windows lastObject];
UIViewController *myRootViewController = frontWindow.rootViewController;
You Can also send Notification whenever you move to root view controller
by adding observer to it.
one way is to use protocol and other way is to pass your root view controller instance to your tableviewcontroller(via view controller) using your custom init method like:
UIViewController.m
- (id)initWithRoot:(id)rootInstance
withNibNameOrNil:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.root = (RootView *)rootInstance;
}
}
RootViewController.m
viewcontrollerInstance = [[viewcontroller alloc] initWithRoot:self withNibNameOrNil:#"viewcontroller"
bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:viewcontrollerInstance animated:YES];
UITableViewController.m
- (id)initWithRoot:(id)rootInstance
withNibNameOrNil:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.root = (RootView *)rootInstance;
}
}
ViewController.m
tableViewInstance = [[tablecontroller alloc] initWithRoot:self withNibNameOrNil:#"tablecontroller"
bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:tableViewInstance animated:YES];
UITableViewController.m
now on table view controller use your root instance(come from view controller) to call the function of root view controller like:
[self.root displayMessage:message];
sorry for the typo. hope this will help.
I've done this many times with code that is exactly the same, but for some reason it isn't working today.
ExampleViewController1 *exampleView = [[ExampleViewController1 alloc] initWithNibName:#"ExampleViewController1" bundle:nil];
[exampleView setProjectName:[[self.projectListArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
NSLog(#"%#", [[self.projectListArray objectAtIndex:indexPath.row] objectForKey:#"name"]);
XAppDelegate.stackController pushViewController:exampleView fromViewController:nil animated:YES]
My NSLog prints out appropriately.
My ExampleViewController1.h file declared like:
#property(nonatomic, strong) NSString *projectName;
I then do this code in ExampleViewController1.m's
-(void)viewDidLoad {
NSLog(#"%#", self.projectName);
self.projectNameLabel.text = self.projectName;
[super viewDidLoad];
}
The results of my NSLogs are curious. The NSLog from my viewDidLoad appears to be getting called before my other one:
2012-04-22 10:59:41.462 StackedViewKit[43799:f803] (null)
2012-04-22 10:59:41.463 StackedViewKit[43799:f803] NewTest
I have confirmed that the (null) value there is from NSLog(#"%#", self.projectName);, but that should be the second NSLog called...I can't figure out why it is coming through first.
Someone requested this code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// random color
self.view.backgroundColor = [UIColor colorWithRed:((float)rand())/RAND_MAX green:((float)rand())/RAND_MAX blue:((float)rand())/RAND_MAX alpha:1.0];
}
return self;
}
As I expected, the problem is that you are trying to access self.view inside the initialization method. So move the line self.view.backgroundColor = ... to the viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.projectName);
self.projectNameLabel.text = self.projectName;
self.view.backgroundColor = [UIColor colorWithRed:((float)rand())/RAND_MAX green:((float)rand())/RAND_MAX blue:((float)rand())/RAND_MAX alpha:1.0];
}
In fact, the documentation of the view property says:
If you access this property and its value is currently nil, the view controller automatically calls the loadView method and returns the resulting view.
So when you call self.view in the initialization method, the view controller will have to load the view (from the nib or using the loadView method). And that's why viewDidLoad is called.
viewDidLoad is called before a view controller is displayed for the
first time, not immediately after initWithNibName.
> viewDidLoad method is called after the view controller has loaded its view
hierarchy into memory. This method is called regardless of whether the
view hierarchy was loaded from a nib file or created programmatically
in the loadView method.
> initWithNibName The nib file you specify is not loaded right away. It
is loaded the first time the view controller’s view is accessed. If
you want to perform additional initialization after the nib file is
loaded, override the viewDidLoad method and perform your tasks there.
You can use App delegate to pass the data from one to another, that is another alternate solution.
you do in initWithNibName method itself. or in viewDidAppear.
Your initWithNibName method should be like this as per as #sch comments;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil] //just set it here first and then check
if (self) {
// do something here;
}
return self;
}
We just need to be smart enough to think about what do we need to in constructor and what do we need to at viewDidLoad (once it had loaded into memory)
I'm developing an iOS 4 application and I have developed some classes that I want to use in others projects.
One of this classes, called MapViewController, is a UIViewController subclass. This class uses a XIB file that I've created with interface builder.
I'm wondering if a use MapViewController in another project as a super class from a new class, How can I use it associated XIB?
I want to reuse MapViewController and its XIB, but I don't know if I have to do something special with the XIB file.
I don't know how to explain this. If you need more details, please tell me.
UPDATE:
I want to create a new class that inherit from MapViewController, like this:
...
#interface NewMapViewController : MapViewController {
...
And, now if I want to continue using the same XIB (the one from MapViewController), what must I do?
Since you are gonna inherit from MapViewController, your MapViewController becomes the super class. And you also have MapViewController.xib. It seems pretty straightforward to me if you use the initializer for NewMapViewController
NewMapViewController.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
NSLog(#"Subclass initWithNibName called");
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
Initialize your NewMapViewContoller like:
//Nib of super class is MapViewController
NewMapViewController *nmapController = [[NewMapViewController alloc] initWithNibName:#"MapViewController" bundle:[NSBundle mainBundle]];
In iphone Application
I need to pass some values to a new viewcontroller object while it create from a method in another viewcontroller class so I can initialize that values in (id)initWithNibName:method of new viewcontroller then I can load those values in viewdidLoad method.
what I want to know is how do I pass the values(parameters) to the constructor(initWithNibName) of a new viewcontrollor Object like constructor overloading in java
give me some code example just showing how initWithNibName called with extra parameters and how to retrieve them in the newly created object
Thanks...
Answer
this is the way I solve the problem "Observation is a object with attributes"
in ViewControllor.h I put
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil set:(Observation *)observation;
in ViewControllor.m file I put
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil set:(Observation *)observation{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization on passed parameter observation object
draftObservation = observation;
}
return self;
}
then I call it this way in another class
ObsevationListView *obsevationListView = [[ObservationViewControllor alloc]
initWithNibName:#"ObservationViewControllor"
bundle:nil set:observer];
[self.navigationController pushViewController:obsevationListView animated:YES];
it works fine. I'm glad if anyone get help from this
You should create another initializer in your class, something like
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andParam:(id)aParam {
...
self.param = aParam;
}
Another solution is to have a property for that parameter and set it either before or after you call using the following code:
initWithNibName:bundle:
I have a uiviewcontroller with two properties: trackName and playerObject. PlayerObject also has a trackName property. I call this uiviewcontroller from my main uiviewController with this code:
SecondaryViewController *nextViewController = [[SecondaryViewController alloc] initWithNibName:#"SecondaryViewController" bundle:nil];
NSString *trackName = #"a track";
nextViewController.trackName = trackName;
[self.navigationController pushViewController:nextViewController animated:YES];
[nextViewController release];
In SecondaryViewController I override the initwithnibname method to set the trackName of the playerObject. I do this with this code:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
playerObject.trackName = trackName;
}
playerObject.trackName = trackName;
return self;
}
Finally my playerObject has all of the view data the SecondaryViewController will need. It looks like:
- (void)awakeFromNib{
NSString *s = trackName;
//more code relevant to the the view controller
}
When I debug, the trackName string in the playerObject is nil. I assume I'm doing something wrong. How can I have this value populated with the trackName I originally passed in the main uiview controller?
It seems like when you are initing the viewController the playerObject variable has not yet been set, could this be possible?
This can sometimes happen when you override initWithNibName:bundle:.
Instead use viewDidLoad to do setup. Apple guarantees all required setup is performed before this method is called (not the case with initWithNibName:bundle:).