I'm a huge noob, let's get that straight.
Currently I have in my header file...
#interface ViewController : UIViewController <UIWebViewDelegate>
...but can I have multiple delegates in the h/m files?
Can I add somehow?
The reason I ask this, is because of a warning I'm getting...
"Assigning to 'id' from incompatible type 'ViewController *const __strong'"
The app works fine, but I want to make sure the code is 100% proper.
(LONG STORY SHORT, I'm trying to add location tracking to my app, and I did, and it works fine, but it's giving me a warning because I'm 100% positive I didn't implement it properly, as I am trying to have multiple "XXX.delegate = self;" going on.
I want to somehow have...
self.locationManager.delegate = self;
AND
tapView.delegate = self;
in the same "-(void)viewDidLoad"...
Again, I expect people to literally say "Wtf are you smoking, you are doing this all wrong", because I am.. I need help. Please help. I've been googling all day.
That was a very long winded way of asking how to do this:
UIViewController <UIWebViewDelegate, UITextFieldDelegate, UITableViewDelegate>
There is no issue in doing this at all. You must specify the protocol to remove the warning
You can confirm multiplay delegates i.e.
#interface ViewController : UIViewController <UIWebViewDelegate,SomeOtherDelegate>
Well, you can conform to multiple protocols in your .h file like that:
#interface ViewController : UIViewController <UIWebViewDelegate, UITableViewDelegate, UITableViewDataSource>
Ad you can also conform to more protocols in your .m file with a private class extension like that:
#interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
Don't mix them up
in .h file
#interface YourControllerClass : UIViewController <UIAlertViewDelegate, UIWebViewDelegate UITextFieldDelegate>
You can add Delegates when ever you need them. These Delegates have their methods defined. You can use their methods as you wish
Related
How you guys slim down your view controllers?, sometimes you end up implementing a lot of protocols in your view controller, so there’s a lot of code inside the controller itself. Reading about how to slim down view controllers in iOS I found that a common way is to move DataSources (http://www.objc.io/issue-1/lighter-view-controllers.html) to other class, but what about other delegates?, or if you create views by code?. First, I think about move each delegate to a NSObject class, so I try this:
self.locationManager.delegate = [[FRRYPetDescriptionViewControllerLocationDelegate alloc] init];
Then I ask in IRC and somebody suggest categories, so this is what I got so far:
// FRRYPetDescriptionViewController.h
#interface FRRYPetDescriptionViewController : UIViewController
#property (nonatomic) CLLocationManager *locationManager;
#property (nonatomic) TPKeyboardAvoidingScrollView *scrollView;
#property (nonatomic) UIView *contentView;
#end
// FRRYPetDescriptionViewController+Protocols.h
#interface FRRYPetDescriptionViewController (Protocols) <UITextViewDelegate, UIActionSheetDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate, MKMapViewDelegate, UIViewControllerTransitioningDelegate, CLLocationManagerDelegate>
#end
// FRRYPetDescriptionViewController+UIAdditions.h
#interface FRRYPetDescriptionViewController (UIAdditions)
- (void)createScrollView;
- (void)createContentView;
#end
// FRRYPetDescriptionViewController+Callbacks.h
#interface FRRYPetDescriptionViewController (Callbacks)
#end
// FRRYPetDescriptionViewController+LocationAdditions.h
#interface FRRYPetDescriptionViewController (LocationAdditions)
#end
This makes me think, what about “private” methods?, do I need to declare all properties in the view controller header file?. What you guys think about this approach or there’s some common pattern to follow to not end with a fat controller?.
Thank you.
The link that you have referred to has beautiful explanation for less bulky controller's programming. But techniques are bit tricky unless you are a seasoned developer. You have asked about multiple techniques in your question. Please check my views on them below: -
Delegates - I personally prefer to keep the delegate code in my controller itself to avoid unwanted confusion specially when you are working with multiple scenarios within the same controller.
Create Views Programmatically - This is the portion where we can cut the large amount of code from UIViewController. Unless it is a single control such as a single label or button, we should make a custom UIView class and let it set all the common properties for view customisation. Controller should only invoke it with necessary parameters.
Properties in Header File - No, concept of data encapsulation says that we should only make those variables public which are required. Rest should move to private domain so that we external objects can't interfere with the class object functionality. So you should declare these properties in class extension (inside .m file). Moreover it is not required to have all variables as properties, when they are private you can declare them as instance variables as property declaration does nothing but to create the getter/setter for that variable.
Private Methods - Same goes to methods as well. If it doesn't have to be exposed to other objects; it should not be in header file. Keep it in extention as private method.
That's a weird one:
I'm using a DMSplitView instance
Dragging it to my AppDelegate.h which creates an outlet like #property (weak) IBOutlet DMSplitView *verticalSplit;
However, whenever I'm trying to access it, in my AppDelegate.m, I'm getting an error:
No visible #interface for 'AppDelegate' declares the selector verticalSplit
How is that possible? I've done that like 10,000 times before. What sort of bug is that? Any ideas?
P.S. Just tried it as an experiment, and it's official: I cannot add any outlet whatsoever. :S
How are you defining DMSplitView? Did you use the #class directive in the header file? Did you import it in the .m file? Just wondering.
I've seen this in some areas of code that I am working with.
searchBar.delegate = (id<UISearchBarDelegate>)self;
My question is...
Why not just make the current class a delegate of UISearchBar by adding <UISearchBarDelegate> in the interface of the class?
Are there times when the above code is better than having the class be a delegate?.
Both ways work for me, but I'd like to learn why I may want to use one over the other.
The cast approach could be considered a cheat. It would be used if the delegate class didn't want to publicly declare the protocol conformance (but then why is it being publicly set as the delegate). Or if the delegate class didn't implement all of the required methods so declaring the protocol conformance would result in warnings.
Generally the better approach is to declare the protocol conformance (either publicly (.h) or privately (.m)).
If you are not using the UISearchBarDelegate in your .h like
#interface ScaryBugData < UISearchBarDelegate>
#property (strong) UISearchBar * searchBar;
#end
then in your .m file then you must do the following to silence the warning
searchBar.delegate = (id<UISearchBarDelegate>)self;
My problem is a follows
I have a UIViewController subclass which holds a UISegmentedController and four tableviews that I layed out in interface builder.
#interface MultiTableHoldingView : UIViewController{
}
#property (strong, nonatomic) IBOutlet DataTV *dsDataTV;
#property (strong, nonatomic) IBOutlet EnviroTV *dsEnvironmentTV;
#property (strong, nonatomic) IBOutlet LocationTV *dsLocationTV;
#property (strong, nonatomic) IBOutlet Note_AnimalTV *dsNoteAnimal;
#property (strong, nonatomic) IBOutlet UISegmentedControl *diveElementSegmentController;
#property (strong, nonatomic) DiveSite* currentSite;
- (IBAction)diveElementSegmentControllerDidChange:(UISegmentedControl *)sender;
-(void) setFreshWaterColor;
-(void) setSaltwaterColor;
#end
setFreshWaterColor and setSaltWaterColour just set the background colour properties of the MultiTableHoldingView instances UIView and the four tableviews it contains. Both these method work fine when called from MultiTableHoldingView's viewDidLoad method. Heres one of them
-(void) setSaltwaterColor{
DLog(#"in set salt water colour");
self.view.backgroundColor= SaltWaterColor;
_dsLocationTV.backgroundColor=SaltWaterColor;
_dsDataTV.backgroundColor=SaltWaterColor;
_dsEnvironmentTV.backgroundColor=SaltWaterColor;
_dsNoteAnimal.backgroundColor=SaltWaterColor;
}
The other is the same except sets to FreshWaterColor - both are #define i have set up.
I use the segmentedController to turn the hidden properties of the various tableviews on and off. All nice and simple. The tableviews are pulling in their data. Working fine.
When selecting one of my tableview cells on one of the tableViews I want to change the background colour of both my tableview ( in fact all of my tableviews ) and the UIView that is the superview
self.superview.backgroundColor = FreshWaterColor;
works fine for reaching back and changing the instance of MultiTableHoldingView views background property but I want to call the instance of MultiTableHoldingView's setFreshWaterColor and setSaltwaterColor methods.
I have imported MultiTableHoldingViews header into the relevant tableview (EnviroTV), so it knows about it its superviews methods. But if I try to call either of the two methods on self.superview the methods do not show up and if i type them in full I get an the following error
no visible interface for 'UIView' shows the selector 'setFreshWaterColor'
So i checked what kind of object the superview was and its a "class of superview UIViewControllerWrapperView"
I search on this and its apparently "
This is a private view used by the framework. You're not supposed to modify it or whatsoever."
I'm obviously missing something here - how should i call the method on the instance of MultiTableHoldingView ?
Thanks in advance
Simon
Doh - its just delegation as danypata mentions in the comments - i've posted exactly how I did this as an answer below. Tried to make it as clear as possible how delegation works
THE SOLUTION
Step one - get more sleep before coding .
This really is basic objective-c stuff - I just went off at a tangent, looking for someway else to do it, getting confused by my discovery of UIViewControllerWrapperView along the way.
The solution, as danypata rightly suggests in the comments, is to use delegate -a common design pattern in Objective-C - just like you do, for example, when you use another class to supply tableview data
As I've been a numpty and wasted hours of my time today I'll try and make the 'how' clear for other relative newbies or people having an off day and not thinking straight.
In my case I set this up as follows
In my subview class's interface file - EnviroTV.h - I define the following protocol just before the #interface declaration
#protocol EnviroTVProtocol <NSObject>
-(void) setFreshWaterColor;
-(void) setSaltwaterColor;
#end
Then in the #interface section of the same file I add a property of type id which must conform the protocol I just declared .
#property (nonatomic, strong ) id<EnviroTVProtocol> colorChangeDelegate;
You make the type an id - a generic object - as you really don't care what kind of object is going to act as your delegate just that it implement the methods that you need it to run. When an object declares itself to implement a protocol its just promising to implement the method(s) that are required by the protocol
So, when I want to run the methods on the superviews class I call
[self.colorChangeDelegate setFreshWaterColor];
Or
[self.colorChangeDelegate setSaltWaterColor];
The final piece of the delegation pattern is to go into the class thats going to be the delegate (in this case my MultiTableHoldingView class ) and state that it conforms to the protocol
I do this in the MultiTableHoldingView.h file
Changing this line :
#interface MultiTableHoldingView : UIViewController
into this line :
#interface MultiTableHoldingView : UIViewController <EnviroTVProtocol>
means this class promises to implement all the required methods of the EnviroTVProtocol.
Luckily I had already written the two methods. So when I compiled it ran correctly
Newbies - don't be afraid of delegation - its awesome and not as complex as you first imagine it to be
Meanwhile, if anyone can explain what UIViewControllerWrapperView is .....
I'm subclassing a UIToolbar because I'm gonna reuse it all over my app. The UIToolbar uses a delegate protocol:
//
// UIToolbarCustom.h
//
#import <UIKit/UIKit.h>
#protocol UIToolbarCustomDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface UIToolbarCustom : UIToolbar {
id <UIToolbarCustomDelegate> delegate;
}
#property (strong, nonatomic) id delegate;
#end
The standford iOS development course teacher recommends to explicit declare all the ivars prefixing it with a underscore, like:
#implementation UIToolbarCustom
#synthesize delegate = _delegate;
#end
But, in this specify scenarion it gives me a error:
error: property 'delegate' attempting to use ivar '_delegate'...
The code works just fine if I use:
#synthesize delegate = __delegate; or
#synthesize delegate;
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
UPDATE
Thank all you guys for all the clarifications and protips, I'm learning a lot. Turns out that I'm new to iOS development (this is my first app second version, so I'm trying to do it right =p). Following the tips I came out with this new header file:
//
// Toolbar.h
//
#import <UIKit/UIKit.h>
#protocol ToolbarDelegate
#required
- (void)tab:(UIBarButtonItem *)sender;
- (void)ok:(UIBarButtonItem *)sender;
#end
#interface Toolbar : UIToolbar
#property (strong, nonatomic) id delegate;
#end
Notes:
The class prefix was removed.
The delegate declaration was removed (I'm using a ios delegate tutorial code, but the code sample uses a older xcode version, where the declaration is needed).
The synthesize was removed, I also didn't knew that we don't need synthesize our properties anymore.
PS: Obviously the code does not work, because the ivar problem. I'm gonna change its names, so I don't need to synthesize it, not sure about what name to use anyways...
What is going on here? Is there a private instance variable in the UIToolbar class named _delegate?
Yes, that's exactly the problem. You need to come up with a different name for your instance variable. __delegate will work, or you could prefix the name with a 3 letter prefix (see last paragraph).
Do note that you've declared your ivar as delegate, then in the synthesize statement told the compiler to use _delegate. Effectively that means that your delegate ivar isn't being used at all. In any case, if you're writing for iOS (as opposed to 32-bit Mac), like you are, you don't need the explicit instance variable declaration in your subclass's #interface section, because the compiler will automatically create it for you.
Finally, it's bad form to name your own subclass something that begins with 'UI', since the UI prefix is reserved for classes that are part of UIKit. You should use your own 3 letter prefix instead, or else no prefix at all. The problem is that a future version of UIKit could conceivably include a class called "UIToolbarCustom", and your subclass would collide with it.
Since last year, when Xcode 4.3 came out, you don't need to synthesize your properties. It is done for you by the compiler (an ivar is generated, and a leading underscore is added to its name). This means that you also don't need to declare an ivar. If you do, be sure to name it something other than _delegate.
So, all you really need is this line:
#property (strong, nonatomic) id<UIToolbarCustomDelegate> delegate;
UPDATE: please see the Andrew Madsen's answer for the full story. Turns out UIToolbar has its own ivar named _delegate. Who knew!