Referencing UIViewController in NSObject - objective-c

I am trying to access UIViewController's view in a NSObject class. The NSObject class is suppose to programmatically change UIViewController's user interface. I tried accessing NSViewController's view in NSObject by using self.view but was told that "request for member 'view' in something not a structure or union.
After a few inquiries, I was told that I need to reference viewController in my NSObject class. I am unsure of how to do this and would appreciate any help or point in the right direction. Thanks!

You should give the NSObject class a property called myController or something in its interface declaration, or pass a ViewController* to any methods that need to access it.
For the property, you can say:
ViewController* myController;
in the NSObject sub-class interface declaration, or for the method way, add an argument to your NSObject sub-class' method:
- (void) someMethodThatTakesAViewController: (ViewController*) theViewController {
//Do your stuff here
theViewController.view = [[UIView alloc] init]; // Or whatever you want to do
}
Hope this was what you were looking for.

Related

Can anyone please help me out? iOS How Datasource methods are implemented? and How do they work?

I am trying to implements my own Datasource methods.Not getting how can we implements.
Datasources and delegates are both implemented using protocols. The difference between the two is that the delegate controls user interaction and the datasource controls data.
This means that your typical delegate method will be called from something like a button click and your datasource method will be called during initialization or refresh of the control. It also means that delegates are more likely to have void methods and data source methods will most likely define a return type.
If you take an example that has a view controller and your custom control, then you would do something like this to setup your datasource protocol.
CustomControl.h:
#protocol CustomControlDatasource <NSObject>
- (NSInteger)NumberOfThingsInControl;
#end
#interface CustomControl : NSObject
#property (nonatomic, weak) id <CustomControlDatasource> delegate;
#end
You could call datasource methods from your init or refresh method and use the result to configure the control however you'd like (don't forget to synthesize the delegate property).
CustomControl.m:
#synthesize datasource = _datasource;
...
-(void)refresh {
NSInteger numOfThings = [self.datasource NumberOfThings];
// Use the result to update the control
...
}
The class that implements the datasource needs to conform to it and implement the datasource method.
MyViewController.h:
#interface MyViewController : UIViewController <CustomControlDelegate> {
CustomControl *coolControl;
}
#end
MyViewController.h:
- (void)viewDidLoad {
[super viewDidLoad];
coolControl = [[CustomControl alloc] init];
[coolControl setDatasource:self];
[coolControl refresh];
}
- (NSInteger)NumberOfThingsInControl {
return 3;
}
I hope this clears things up a bit. protocols are an awesome way to have objects communicate.
You can read more in the documentation:
Working with Protocols
Delegates and Data Sources

Objective-C: Where to initialize a delegate

I don´t fully understand how to use the Delegation pattern in obj-C. Basically I have a class: DigGameControlLayer.h and in it´s header I define a protocol with one required method that all users of this class needs to implement. Then I create the delegate property that I use within the code like any other property to delegate responsibility of what the moveObjectToPosition: method should do. So far so good I hope.
//DigGameControlLayer.h
#protocol DigGameControlLayerDelegate <NSObject>
-(void) moveObjectToNewPosition: (CCSprite *)object atSpeed:(float)moveSpeed;
#end
#property (assign) id <DigGameControlLayerDelegate> delegate;
Then the class that is using that class (in this case DigCharacter) says it adheres to the DigGameControlDelegate protocol
#interface DigGoblinPlayer : DigCharacter <DigGameControlLayerDelegate>
But what I don´t understand is where do i Initialize and set the delegate property a declared? Cause currently it does nothing when I use it in DigGameControlLayer since it´s null
[self.delegate moveObjectToNewPosition:object atSpeed:moveSpeed];
You can pass the delegate in the init method like so:
DigGoblinPlayer* player;
player = [[DigGoblinPlayer alloc] initWithName:(NSString*)name delegate:self];
Or set it separately:
DigGoblinPlayer* player;
player = [[DigGoblinPlayer alloc] initWithName:(NSString*)name];
player.delegate = self;
Which style you choose depends on if you always want/need a delegate, or if you want to be able to change/reset it later on.
In some cases you don't want the delegate to be a public property; then you'd use the first style.
You see a lot of example of this in the iOS SDK like here.
Note that self --which is just an example, and could an other object of course-- needs to implement this delegate. And name is something I made up.
in DigGoblinPlayer
implement the method
-(void) moveObjectToNewPosition: (CCSprite *)object atSpeed:(float)moveSpeed
{
}
this method will be called when the method calls in DigGameControlLayer
[self.delegate moveObjectToNewPosition:object atSpeed:moveSpeed];

Calling a method from another 'm' file

The bulk of the code for my app is in a 'm' file called MyViewController. The app implements a custom UIView which contains a UIWebView object. The code for the UIView and UIWebView is kept in a separate 'm' file called CustomUIView.
I have managed to override clicks on URL hyperlinks in the UIWebView object using a delegate. However, I would like to have these clicks launch a method that is stored in my main app code. This method is called "popupView", and takes a single argument, "inputArgument". The inputArgument is the text of the URL the user clicks on. In fact, this method is the very same one that causes my custom UIView to launch.
Anyway, what I'd like to do is have my overridden URL clicks cause the popupView method to launch, thus causing another UIView to open on top of the one that was clicked on.
The problem is that the 'm' file where the URL clicks are detected can't see the 'popupView' method as it is included in the MyViewController 'm' file. How do I call the popupView method from another 'm' file?
Directly
Declare MyViewController's method -popupView: in MyViewController.h.
#import MyViewController.h in CustomUIView.m.
Give CustomUIView a reference to the [one] instance of MyViewController, for example by way of an #property declared in CustomUIView.h.
For (1), the #interface of MyViewController (in MyViewController.h) should look a bit like this
#interface MyViewController : UIViewController
{
//....
}
- (void)popupView:(NSString *)urlText;
//....
#end
For (2), UIViewController.m should have the following somewhere near the top
#import "CustomUIView.h"
#import "MyViewController.h"
For (3), the #interface in CustomUIView.h should look something like
#interface CustomUIView : UIView
{
//....
}
#property (nonatomic, weak) MyViewController *viewController;
#end
This property will need to be set some time after the instance of CustomUIView owned by MyViewController is created. If your CustomUIView is in MyViewController.xib, you can set this property on it by adding the keyword IBOutlet to the property's declaration like this
#property (nonatomic, weak) IBOutlet MyViewController *viewController;
and pointing this property to "File's Owner" in the XIB. If instead, you create the CustomUIView programmatically, you can set this property on it as soon as you have initialized it.
Delegate
This, however, is far from being a best practice. It would be much better to make use of the delegate pattern. To do this, you'll need to
Define a delegate protocol.
Add a "delegate" #property to CustomUIView.
Call the delegate methods on the delegate object at the appropriate times.
Implement the protocol in MyViewController.
Set the "delegate" #property of the instance of CustomUIView owned by the MyViewController instance to be the MyViewController instance.
Let's call our delegate protocol something imaginative like CustomUIViewDelegate. For (1), we'll declare it at the top of CustomUIView.h as follows:
#class CustomUIView;
#protocol CustomUIViewDelegate <NSObject>
- (void)customUIView:(CustomUIView *)customView didSelectURLText:(NSString *)urlText;
#end
Notice that we've had to forward declare our class CustomUIView so that the compiler is able to make sense of the type of the first argument in the protocol method customUIView:didSelectURLText:.
For (2), we'll do something quite similar to (3) above: Your CustomUIView #interface will look something like
#interface CustomUIView : UIView
{
//....
}
#property (nonatomic, weak) id<CustomUIViewDelegate> *delegate;
#end
Again, if we're going to set this property in Interface Builder, we'll need to use the IBOutlet keyword to announce it to IB:
#property (nonatomic, weak) IBOutlet id<CustomUIViewDelegate> *delegate;
For (3), we need to call the delegate method customUIView:didSelectURLText: on our delegate object self.delegate at the appropriate time.
In your question, you wrote
I have managed to override clicks on URL hyperlinks in the UIWebView object using a delegate.
So, let's say that CustomUIView has an instance method
- (void)didSelectURL:(NSURL *)url
{
//....
}
which you call when the user selects a link in the UIWebView. The CustomUIView's delegate needs to be informed of this:
- (void)didSelectURL:(NSURL *)url
{
//...
if ([self.delegate respondsToSelector:#selector(customUIView:didSelectURLText:)]) {
{
[self.delegate customUIView:self didSelectURLText:url.absoluteString];
}
}
Notice that we check first whether the CustomUIView instance's delegate object implements the selector of interest (customUIView:didSelectURLText:) by calling respondsToSelector: on it.
For (4), we'll need first to add <CustomUIViewDelegate> to MyViewController's #interface declaration and be sure to #import CustomUIView.h into the file where we use the symbol CustomUIViewDelegate. Our MyViewController's #interface will look something like this:
#import "CustomUIView.h"
#interface MyViewController : UIViewController <CustomUIViewDelegate>
{
//....
}
//....
#end
More importantly, we need to implement the CustomUIViewDelegate protocol in MyViewController's #implementation; so far we've only declared that MyViewController adopts it.
To do this, since our protocol consists of only one method, we'll need only to add our own implementation of -customUIView:didSelectURLText:. Our MyViewController's #implementation will look something like this:
#import "MyViewController.h"
#implementation MyViewController
//....
- (void)popupView:(NSString *)urlText
{
//....
}
#pragma mark - CustomUIViewDelegate
- (void)customUIView:(CustomUIView *)customView didSelectURLText:(NSString *)urlText
{
[self popupView:urlText];
}
//....
#end
Finally, for (5), we'll need to set the delegate property of the instance of CustomUIView owned by the MyViewController instance. I don't know enough about MyViewController's relationship with its CustomUIView instance to do describe how to do this definitively, but I'll provide an example: I'll assume that you programmatically, in -[MyViewController loadView] add the CustomUIView as a subview of MyViewController's view. So your implementation of -loadView looks a bit like this:
- (void)loadView
{
[super loadView];
//....
CustomUIView *customView = //....
//....
[self.view addSubview:customView];
//....
}
All that remains to do at this point is to set the delegate #property of the local variable customView to self:
customView.delegate = self;
Edit: Updated (5) in light of new information about the relationship between CustomUIView and MyViewController.
In your comment, you write that your CustomUIView is added as a subview of cvc.view where cvc is an instance of CustomUIViewController in CustomUIView's method -[CustomUIView show]. On account of this, you note that writing customView.delegate = self; is the same as writing self.delegate = self, which is clearly not what you want to do.
You want to set the CustomUIView's delegate property to be the instance of MyViewController. Consequently, your method -[CustomUIView show] should look something like
- (void)show
{
//....
[cvc.view addSubview:self];
self.delegate = mvc;
}
where mvc is the instance of MyViewController.
Well, since you are writing the CustomUIView, why not implement a constructor like initWithPopupDelegate:(MyViewController *)delegate and keep a reference to the MyViewController instance that way in an instance variable, then call the method on that.
(Add #class MyViewController; at the top CustomUIView.h, and #import "MyViewController.h" at the top of CustomUIView.m so the compiler knows the class you are using.)
Alternatively, if there is ever only one MyViewController instance, you can define a class method for MyViewController, e.g., + (MyViewController *)instance, and have that return a reference to the one instance (which you store in a class variable and set the first time when you create the instance, see “singleton pattern”). But without knowing the specifics of your code, I would suggest the first solution (delegate) as simpler and more flexible.

How to Access parentViewController's methods and properties

I've been searching for a solution for this problem but I couldn't solve it!
I tried
mapViewController = (MapViewController*)self.parentViewController;
but it doesn't work.
you can do like this ..
in your class .h file
make a member variable
#interface SomeClass: NSObject
{
UIViewController *controller;
}
when you initialize the class make it controller to self ...that way it will work the same way as
SomeClass *class = [[SomeClass alloc]init];
class.controller = self;
now you can use the parent properties and methods..However you will still need to typecast it to (MapViewController*)controller so that it autocompletes its methods.

Accessing cocoa interface builder controller methods

So I have an objective-c project that uses a controller class. This interfaces with interface builder via IBOutlets.
My understanding is that the controller gets initialized by loading the user interface (as it is added to interface builder as an object). I would then like to use the controller's getter methods to return values that are in the IBOutlet fields.
So, to clarify what I mean with some code, here's my controller interface/implementation:
#interface controller : NSObject {
#private
IBOutlet NSTextField *name;
}
-(NSString*) name;
#end
Then, in my implementation, I have:
-(NSString*) name
{
return [name stringValue];
}
in a third class, I'd like to be able to write:
NSString blahblah = [controller name] and have the value of blahblah assume the value of whatever is in the controller's IBOutlet "name" field.
Hopefully this makes sense. When I try and do it this way I get "Semantic Issue: Method '+name' not found (return type defaults to 'id')"
Why? Where is the controller object actually substantiated and where, and how do I access it's fields?
You have to instantiate the controller by using [[controller alloc] initWithNibName:nibName bundle:nil];
By just using [controller name] you are calling a class method. Also it should be NSString *blahblah
You should read this document:
http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html#//apple_ref/doc/uid/TP40007594