Assigning another viewcontroller at initWithNib - objective-c

I am just curious if lets per say I have a singleton property of webView I am trying to assign at the initialization point of another viewController. The compiler is generating the error indicating "Incompatible pointer types".
I am not sure why it is doing so, as the Super Class of that Class is still UIViewController. Any help here would be really appreciated.
Thanks.
Code below:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nil bundle:nil];
if (self) {
// Work your initialising magic here as you normally would
if ([[CartCheckout sharedInstance] universalVC]) {
//self = [[CartCheckout sharedInstance] universalVC];
NSLog(#"testing");
self = [[CartCheckout sharedInstance] universalVC];
}
NSLog(#"initWithNibName allocated");
}
return self; }

This is happening because the view controller of the actual instance you are trying to do the assignment to is not of the correct type, it doesnt matter that they share a super class.
self in this case is of one and only one type, the type of the view controller subclass.
Also, even if they were the same type, Objective C is not going to let you replace the instance of the class in an init method with anything.
init methods are instance allocation methods, if you return a pointer to something besides the instance you are actually in, you are going to crash immediately following.
So you have two problems, one, you are trying to inject a singleton instance into an init method, and two you are trying to hijack the container of a view.
Neither of these will work. Instantiate the correct type of viewController to go with your view at the time you need it.
What you want instead is this:
MyUniversalViewController *universalVC = [MyUniversalViewController alloc] initWithNibName:#"blabla
Trying to switch types in the constructor is too late.

Related

Use self as parameter in a singleton

I have the following method-header in a singleton:
-(int) reconnectToServerForClass:(id)myClass
The parameter myClass is always the self-object of the calling class. Different ViewControllers in my project call this method so my question is this:
Is it possible to access myClass.view or what can I do to achieve that?
my intention is that I want to show a progress-hud for every ViewController that calls the method:
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:myClass.view animated:YES];
Isn't there the need for casting myClass before I can access the view-property?
If I understand correctly you can do the following:
-(int) reconnectToServerForClass:(UIViewController *)myClass
{
//myClass.view
}
or inside the method
-(int) reconnectToServerForClass:(id)myClass
{
if([myClass isKindOfClass:[UIViewController class]])
{
UIViewController *viewController = myClass; //edit as suggested by Peter Segerblom
//viewController.view
}
}
Which ever option you choose is that it will depend on how you use it and how you want to manage or limit the callers, in option 1 the parameter must be a sub class of UIViewController and the same for option 2 but the difference is that you can pass in anything but if the type is not UIViewController it will just do nothing.
Disclaimer: This code is not tested and typed from memory, so it might not compile, let me know if you come across issues and I will edit answer.
Yes.
If you want to access it from the singleton class, you make a member or property of which is a pointer to a view, then set that in reconnectToServerForClass: and access it as you would any other member.
If you want to access it from outside, you do the same, and do something like [[MySingleton instance] view]
Be aware that dragons lie ahead of your path, you will need to make sure that views "unset" this property before they are destroyed, otherwise your singleton might try to access a no-longer-existing view instance.

In Objective-C how do you entirely replace a method of a parent class, while preserving that parent method's inherited functionality?

Basically I have a class hierarchy something like this:
NSObject
MySpecialController
MyExtraSpecialController
Each of these has an init method, and each implementation calls super first to let the superclass initialize itself first, all the way up the chain. For lack of better terminology I would say that each class "augments" its super class' behaviour.
But let's suppose I want to "replace" my super class's behaviour entirely (simply because I want to specialize it further for a particular app, but without cluttering the generic reusable super class. So it is assumed that I have intimate knowledge of the super class). The actual change that I want to do is replace a property with one of a more specific class type. To fully implement this I need the init method to instantiate an instance of widget of the appropriate class. So if I instantiate a MySpecialController, its widget property should be of type MySpecialWidget; but if I instantiate a MyExtraSpecialController, its widget should be of type MyExtraSpecialWidget:
//MySpecialController:
#interface MySpecialController : NSObject
#property (strong, nonatomic) MySpecialWidget *widget;
#end
#implementation MySpecialController
-(id)init {
if (self = [super init]) {
self.widget = [MySpecialWidget new];
}
}
#end
//MyExtraSpecialController:
#interface MyExtraSpecialController : MySpecialController
#property (strong, nonatomic) MyExtraSpecialWidget *widget;
#end
#implementation MyExtraSpecialController
-(id)init {
if (self = [super init]) {
self.widget = [MyExtraSpecialWidget new];
}
}
#end
Now this works in the sense that MySpecialController works, and can be used by anyone with the public API. And MyExtraSpecialController also works, and follows proper separation of concerns as it assumed nothing about the superclass's behaviour. This is the type of subclass one would create of a framework or library class: robust and unassuming.
What actually happens though is that when I create a new instance of MyExtraSpecialController, its superclass first instantiates a MySpecialWidget, and then it immediately deallocates that instance and replaces it with an instance of MyExtraSpecialWidget. Sure this works, but since I DO have intimate knowledge of the superclass (which basically means that I know exactly what its init method does, so I can safely replace it without needing to call it first), I want to avoid this problem and only instantiate a single widget (it just so happens that creating a widget is really expensive and isn't premature optimization). So I want to replace super's implementation entirely so that it doesn't create a widget, and will replace everything else that it does based on my intimate knowledge, but, and this is key, I still want to call init further up the chain because I don't know what my replaced class' superclass' init method does (NSObject in this case), as this is a class I don't have intimate knowledge of.
The immediate solution that comes to mind is to use the Objective-C dynamic runtime to get hold of the grandparent instance, and just call its init (which will then take care of calling up the chain if it needs to), therewith bypassing super. But whenever I find myself about to do something like that I always wonder if there is a better approach altogether--conceptually speaking, i.e. to replace rather than augment a superclass' method. Is there?
You could remove the instantiation of self.widget from the init functions and implement a custom "lazy" getter function instead:
- (MySpecialWidget *)widget
{
if (_widget == nil) {
_wigdet = [MySpecialWidget new];
}
return _widget;
}
Then you can override this method in the subclass. The widget will be created on the first access to self.widget, and either the superclass or the subclass getter is called.
One easy way to solve this would be to create a hook for making the widget.
#implementation MySpecialController
-(id)init {
if (self = [super init]) {
self.widget = [self makeWidget];
}
}
- (MySpecialWidget*) makeWidget
{
[MySpecialWidget new];
#end
Then your subclass can override makeWidget to return a VerySpecialWidget. This makes sense when you don't want clients to know about these widgets.
In your scenario, it's possible that clients know something about the widgets -- e.g. they want a VerySpecialController in order to get a VerySpecialWidget. If that's the case, you might want to let the client pick the widget:
[MySpecialController initWith: [MyVerySpecialWidget new]];
If the widget is the primary force for making the subclass, either approach may eliminate the need to sprout the subclass in the first place.
The second approach has the additional advantage of making unit testing easier; you can build a MySpecialController and pass it a dummy, stub, or mock without any fuss:
[MySpecialController initWith: [MyTestObjectThatPretendsToBeAWidget new]];
But the first pattern is cleaner if the clients shouldn't know anything about widgets.
One approach is to add an instance method -widgetClass to MySpecialController
#implementation MySpecialController
- (id)init
{
self = [super init];
if (self) {
self.widget = [[[self widgetClass] alloc] init];
}
return self;
}
- (id)widgetClass
{
return [MySpecialWidget class];
}
//...
#end
and override that method in MyExtraSpecialController
#implementation MyExtraSpecialController
- (id)widgetClass
{
return [MyExtraSpecialWidget class];
}
//...
#end

Why is my method not found?

I have a custom init method for my SecondViewController : UIViewController
-(id) initWithFirstViewController:(FirstViewController *)theFirstViewController
{
self = [super init];
fvc = theFirstViewController;
return self;
}
So in my FirstViewController I call this init method with an instance of the FirstViewController as a parameter. Somewhere else in the SecondViewController I use this passed intance:
[fvc setSomething];
The method is executed but I get a warning:
Method -setSomething not found (return type defaults to id)
How to fix this?
In this case, it's a matter of #importing the corresponding .h file so the compiler knows about the method.
Additionally, you should retain theFirstViewController as chances are that it gets released and a different object is created at exactly the same memory location (to which fvc is still pointing). So you should do fvc = [theFirstViewController retain]; as you are "holding on to" the first view controller (you want to make use of it later on). Don't forget to release it in your dealloc.

Can you accomplish some form of dependency injection in objective-c?

Currently I'm hard coding another object directly when needed and I'd like the ability to take this in through the init method (I assume?). In the code below I create a new HatService in the viewDidLoad method and I'd prefer not to do this this for testability / coupling reasons.
- (void)viewDidLoad
{
[super viewDidLoad];
HatService* hatService = [[HatService alloc] init];
[hatService getHatById:self];
}
First question - How should this be done in objective-c?
Second question - Should I be worried about this or doing it at all?
Update
Here is what I'm starting with but I never seem to hit the first init method during runtime. I have both declared in the interface - anything else I missed that would allow me to override this init method and inject the service dependency?
Note - I can hit this manually when I create the object myself but when the appDeleage does the work I don't see it hit this (how does the app delegate create this object without calling my init method?)
-(id)initWithHatService:(HatService *)service
{
if (self = [super init])
{
[self setService:service];
}
return self;
}
-(id)init
{
HatService* hatService = [[HatService alloc] init];
return [self initWithHatService:hatService];
}
The designated initializer for UIViewController is - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle. You'll need to override this method if you want your view controller to be properly instantiated from a nib file, if that's what you're trying to do. Without seeing more code, it's impossible to tell, but this method is definitely being called somewhere.
Second, you need to re-write your -init method to look like this:
- (id)init {
return [self initWithHatService:nil];
}
Every init method should call your designated initializer.
Finally, when you're dealing with view controllers, folks usually don't pass in properties in the init method. Instantiate the new controller, then pass it whatever service properties you like.
MyViewController *newContrlr = [[MyViewController alloc] initWithNibName:nil bundle:nil];
newContrlr.hatService = [[[HatService alloc] init] autorelease];
If you're asking how to pass an object to another object's init method, just declare your init method as taking one or more arguments. i.e. - (id) initWithHatService:(HatService *)serv; init methods aren't special in any way except convention in objective-c.
Unrelated: your -getHatById: method is curious. What are the memory management semantics of that? get-prefixed methods are pretty uncommon in Cocoa programs.
It's quite easy to implement the dependency injection design pattern in Objective-C. You could do it manually by creating an 'application assembly' class that defines individual collaborators.
Alternatively, you could use a framework to assist. I recently created a DI container called Typhoon: http://www.typhoonframework.org

in objective-c initializing an object and giving it an instance name

in cocos2d-iphone I have a CCLayer class called GameScene
I want to use this class from another class however I dont know the name of the instance of the GameScene class
I initialized an instance of GameScene class as follows
-(id) init {
if ((self = [super init])) {
however this will not give me the name of the instance
I read in documentation that a method called initWithName can be used so I tried something like this but it does not work it gives me warning:
In function '-[GameScene init]':
warning: 'CCLayer' may not respond to '-initWithName:'
the code I tried is
-(id) init {
if ((self = [super initWithName:"gamescene"])) {
I will need only one instance of this class through the game but I cant catch a handler of that instance so I can use it from other classes?
any Idea
Many Thanks
update:
Hello
I am going to update the code to let you know that I have tried your solution but it dosnot seem to work yet
in the MyAppDelegate.h I have this lines of code:
firstly I have defined the app delegate to share it with other classes
MyAppDelegate.h
#define AD (MyAppDelegate *)[[UIApplication sharedApplication] delegate]
and in the MyAppDelegate.m I have the following code:
gs = [[GameScene alloc] init];//this is the gamescene
sc = [gs scene]; //this calls the method -(id)(scene)
[[CCDirector sharedDirector] runWithScene: sc]; //runwithscene
now when I tried to use the gs within other class -for example player.m class-
player.m
GameScene* gs = [AD gs]; //retrieving the instance from appdelegate
[gs updateScoreByAmount:5];/calling the method "updateScoreByAmount"
the results , guess what happens?
the program runs without errors however gs instance seems to be different than the one which is run by the appdelegate since this method "updateScoreByAmount" does not affect the scene which run by the runWithScene in the appdelegate
any idea?
Many Thanks to all those who have tried to help
If I am understanding you correctly, you need a reference to an instance of the GameScene class? If that is the case, it depends how the object is created. You probably are creating the instance from some controller class and it would look something like:
GameScene *gameScene = [[GameScene alloc] init];
Here, gameScene would be the reference to the instance you need.
ahmed,
Instead of storing a pointer to your top level scene, you can do this to get access to it:
GameScene* myScene = (GameScene*)[[CCDirector sharedDirector] runningScene];
CCDirector is a singleton, and it knows what scene it's currently running, so you don't need to keep a pointer to it, you can use the above way of getting to it when you need it.
Because GameScene is a child of CCScene your running scene will be your GameScene object.
Hope that helps.