I want to have a custom initWithNibName, basically passing in another NSString as a type to determine some logic inside this UIViewController based on the type. So I set is as follows:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andFeedType:(NSString *)feedType
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
Does this even make sense? As I don't see this type of init's quite often. If not then what is the best way to do this?
It makes perfectly sense to me. This is the way you would override an initializer to add some custom initialization in Objective-C. What do you think is wrong with it ?
Yes it makes sense. In addition, if you want to keep clean your init you could do the following:
- (id)initWithFeedType:(NSString *)feedType
{
self = [super initWithNibName:#"YourNibName" bundle:nil]; // nil is ok if the nib is included in the main bundle
if (self) {
// Set your feed here (copy it since you are using a string)
// see the edit
myFeedType = [feedType copy];
}
return self;
}
For further info see the post initWithNibName-bundle-breaks-encapsulation by Ole Begemann.
Hope that helps.
Edit
If that feed property cannot be accessed by external objects, create a class extension for your controller like the following:
//.m
#interface YourController ()
#property (nonatomic, copy) NSString* myFeedType;
#end
#implementation YourController
#synthesize myFeedType;
#end
It does make sense. You are creating you own initializer, tailored to your needs. Also, you are doing what you should, which is calling the designated initializer (in the case of UIViewController initWithNibName:bundle:) inside your custom init method.
Wait!
There is one reason why it may not be best: this method is not called when your view controller is loaded from a storyboard. For this reason I recommend using viewDidLoad: instead for the custom logic, and setting your custom string as a property.
Related
I am trying to write a global function however keep getting the error "No visible interface...." when i try and call it.
Popover.h
#import <Foundation/Foundation.h>
#interface Popover : NSObject{}
- (void)PopoverPlay;
#end
Popover.m
#import "Popover.h"
#implementation Popover
- (void)PopoverPlay{
NSLog(#"I Work");
}
#end
In View.m i am adding the import "Popover.h" but i cant get rid of the error message when i try and run.
#import "View.h"
#import <QuartzCore/QuartzCore.h>
#import "Popover.h"
#interface View ()
{
}
#end
#implementation View
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
}
- (void)viewDidLoad{
[super viewDidLoad];
}
- (IBAction)ButtonPress {
[self PopoverPlay];
}
Any ideas
Thanks
The code you've shown is the declaration and definition of a class that contains a single instance method. To use it, you'll need to allocate an instance of Popover with code that looks something like:
#import "Popover.h"
//...
Popover *pop = [[Popover alloc] init];
[pop PopoverPlay];
//...
When people talk about "global functions" they don't usually mean instance methods (or even class methods), so I doubt this is quite what you're after. Perhaps you mean an actual function that you can call from other parts of your code? You'd do that the same way you do in C:
void foo(void);
void foo(void)
{
NSLog(#"This works");
}
If you add the prototype (first line) to a header file, you can use the function anywhere in any file that includes that header.
Update:
- (IBAction)ButtonPress {
[self PopoverPlay];
}
The problem here is that you're sending -PopoverPlay to self, but self in this case represents an instance of View. You need to send -PopoverPlay to an instance of the class that implements it, which is Popover. See my example above. (BTW, your interface and implementation don't match: one is PupilView and the other is View.)
To call the method you wrote, you need to do something like:
Popover *myPopover = [[Popover alloc] init];
[myPopover PopoverPlay];
What you have is an instance method. Because your method doesn't rely on any instance variables, you could make it a class method by changing the - to +:
+ (void)PopoverPlay;
and
+ (void)PopoverPlay{
Then you don't need to initialize a new Popover; you can just call:
[Popover PopoverPlay];
I'm running into an issue where a derived class sets a property defined in the super class in its initWithNibName call and by the time viewDidLoad is called, the property is magically undefined again. It goes something like:
#interface BaseClassController : UIViewController
{
}
#property (copy, nonatomic) NSString *myString; // synthesized in the .m
in another file
#interface DerivedClassController : BaseClassController
{
}
and in its implementation:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
NSLog(#"Setting MyString stuff");
self.myString = #"Hi Mom";
NSLog(#"Done setting myString");
}
return self;
}
- (void)viewDidLoad
{
NSLog(#"MyString is %#", self.myString); // output as (null)!!!
[...]
}
According to the output of NSLog the order is correct, I know for a fact that viewDidLoad isn't being called first: first the initWithNibName method, then viewDidLoad. viewDidLoad reports self.myString as (null) every single time. However if I move the initialization of myString down to viewDidLoad, everything works fine. Why? I must be missing something really obvious here..
Edit:
Not sure if this makes a difference, but the DerivedClassController is the root view controller of a navigation controller that's being presented modally (for all sorts of legacy reasons).
Edit 2:
The code works as expected in a stand-alone xcode project, it fails when imported into the project where I'll ultimately need to use it.
Are you certain that you're logging from the same controller both times? Like, perhaps you're calling initWithNibName:bundle: on one controller, but then viewDidLoad is actually called on another controller?
Is there any reason why you have it set to copy?
Try setting the property to:
#property (nonatomic, strong) NSString *myString;
i have 2 classes . in my first class i have one label. now i have to give input for that label from my second class.
here is my code.
IBOutlet UILabel *label1;
#property(nonatomic, retain) IBOutlet UILabel *label1;
#synthesize label1;
I call this label like this.
I import my class1 and create object like classone.
I checked(NSLog print)class and that method will be called but that input won't come.i checked that label its also connected to my class.because i give same input in my viewDidLoad that time its working fine.
NSString *ram= #":13123123312";
classone.label1.text= ram;
guide me where i'm doing wrong.
Setting values of previous views is trickier than this. What it the view has been removed by the OS under memory pressure?
The proper way of setting these values is to use the MVC pattern that is used throughout the Cocoa frameworks. Your second view controller sets a property of the previous view controller. And when the previous view needs to be shown, it takes its value from this property.
The usual way to correctly hook up a view controller to talk back to a another view controller lower in the stack is to use a delegate protocol.
I wrote an example of this, DelegationExample,a while ago which shows how a textfield in the first view is populated by a textfield's value in the second view controller using a delegate protocol. You might find it useful to see how I have done this as an example.
Update
I've updated the link to a new project for iOS6 with ARC and Storyboards
Take one NSString variable in AppDelegate class and synthesize it properly. And store the value of the second class's variable to that like:
appDelegate.strLbl = [NSString stringWithformat:#"%#",strVal];
and then copy that value to the label in first class like:
lblVal.text = [NSString stringWithformat:#"%#",appDelegate.strLbl];
Hope that helps you. Thanks.
Actually you should have the reference of the first class in the second class. You should not allocate a new instance. If you create new instance, then the instance for which you have set the label value is different from the actual one which you will see on clicking back.
I guess you got this.
Aadhira was right, when u create a new instance of class1 in class2 its wrong,
You have to get the original instance of class1, this can be achieved by creating a static function which returns current instance of class1, as shown below
static classone* sInstance;
#implementation classone
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
sInstance = self;
return self;
}
+(classone*) getInstance {
// NSAssert (sInstance!=nil, #"classone:getInstance: called when singleton was not initialized!");
return sInstance;
}
I just started to learn iOS programming and I have a problem with inheritance. There are 2 files.
First file
Header
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
int x;
}
#end
Implementation:
#import "ViewController.h"
#import "NewClass.h"
#implementation ViewController
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
x = 999;
NewClass *myClass = [[[NewClass alloc] init] autorelease];
}
#end
Second file
Header:
#import "ViewController.h"
#interface NewClass : ViewController
#end
Implementation:
#import "NewClass.h"
#implementation NewClass
-(id)init {
self = [super init];
if (self != nil) {
NSLog(#"%i",x);
}
return self;
}
#end
In ViewController I set x to 999, and in NewClass I want to get it, but when I call NSLog(#"%i",x); it gives me 0.
Where did I make a mistake?
You have a timing problem.
The init method gets called first (at all levels of the inheritance hierarchy, so in both ViewController and NewClass). This is when you print out your value of x, when it is still zero.
The viewDidLoad method only gets called much later, generally at a point after a view controller's view has been added to a superview. It's functionality that's specific to the UIViewController class.
To make your example work, put an init method in your ViewController class that looks like the one in your NewClass class, and set x there.
Also, you don't need to create a NewClass instance within ViewController. When you create a NewClass object, it is automatically a ViewController as well. In the same way that a dog is an animal automatically, and so is a cat. When you create a dog, you don't want to create an animal as well!
As sidyll says, you should probably do a bit more reading about how inheritance works, I'm afraid!
You need to review you OOP concepts. Object-Oriented Programming with Objective-C is a must.
Your class NewClass indeed inherits the x variable, but not it's value. When you create an instance of it, you're creating a shiny new instance whose values have nothing to do with the parent class.
Another point of view to help you is that x was set in a object of ViewController class. The NewClass inherits from ViewController class, not from an arbitrary instance (object, where you set x).
That's because -viewDidLoad is not called until well after -init returns. Your superclass should do configuration like that in its -init method.
I've noticed that if you load connected views from a nib you have to override initWithCoder if you want to add initialization code because the designated initializer doesn't get called (which does make sense), and if you don't load the view from a nib then the same code needs to be executed in the designated initializer.
So in order to handle both cases, you need the same initialization code in both methods.
This is the best solution that I have come up with so far, but I have to wonder if there's some more conventional way of doing this. This code is in a UITableViewCell subclass but it could be any UIView really:
/*
* Seems like there should be a standard method for this already.
*/
- (void)didFinishInitializingOrUnacrhiving {
/*** Do stuff that makes the most sense to do in an initializer. ***/
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self didFinishInitializingOrUnacrhiving];
}
return self;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self didFinishInitializingOrUnacrhiving];
}
return self;
}
So any thoughts on this? Is this the "right way" to do things, are there potential pitfalls here, or am I just totally missing something?
I explained this in another answer see Does interface builder use the init method to initialize view controllers?
I do exactly the same thing, except that I'm lazy and my method is usually called -didInit.