Using mapView:didAddAnnotationViews: from MKMapViewDelege and MGLMapViewDelegate errors - ios

In my UIViewController I use both MKMapView and a MGLMapView. I need to use both of their delegate methods including mapView:didAddAnnotationViews: which is named the same for both maps. Xcode doesn't like this:
Is it possible to use both of these delegate methods in the same viewController?

I'm not sure if this will work, but you could try declaring the method just once, like this:
- (void)mapView:(id)mapView didAddAnnotationViews:(id)views {}
And inside the method you check the class of the mapView and do what you must do in each case

Related

How does iOS delegation actually work?

I understand how to use delegation with iOS objects that already exist. For example, if I create an instance of a UITableView, and my view controller conforms to the UITableView delegate, I can implement the various methods of the UITableView delegate. My newly create table can receive notifications, for example, when didSelectRowAtIndexPath is called.
My question is why did my table get this particular delegate callback? My understanding is that the delegate is just a list of methods with no implementation. It seems to me there must be a lot more going on. What is really going on "behind the scenes"?
Image if I were to rename all the delegate methods to the following:
- mysteryMethod1
- mysteryMethod2
- mysteryMethod3... Etc
One of these methods is responsible for setting the height of a row at a particular index. Another one these methods will be responsible for editing a particular row.
Everything I read about delegation says the delegator makes a contract with the delegate. The delegate promises to implement the methods. When it does, somehow everything is wired up correctly and everything magically works. What is the magic that I'm not seeing?
I think that in order to know how delegates actually work you should create your own custom delegate first, that way you will see that there is no magic under the hood, you probably can't see the implementation of the actual apple build in delegate methods but I assure you that there is a lot of logic implemented in those but it's just not available for privacy reasons I assume.
When you create your custom delegate let's say for example...
You have Class A and in this class, you start by creating a protocol
protocol ClassADelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
In this class you have a delegate property like this.
weak var delegate: ClassADelegate?
Let's say that this class is a Viewcontroller and you have an IBACtion on it like a UIbutton, and your goal is that when you tap that button another ViewController in your app change its background color to blue. Inside this action in Class A you do this...
func someAction() {
delegate?.changeBackgroundColor(.blue)
}
,
Let's say that the "magic" happens here in class A, by the way if you are thinking in delegates using UITableview think that UItableView is class A.
ok so now you have Class B that is where you want to change the color right?
Well now class B needs to conform to the protocol like this, just like you also conform to the protocol UITableViewDelegate etc.
class ClassB: UIViewController, ClassADelegate {
}
Now think of the word delegate for a second and think what that means, you are just delegating responsibility to somebody else, right? and yes, in this case, ClassB is going to be the delegated, for that we need to have an instance of Class A in class B just to have access to it's delegate property.
let classa = ClassA()
classa.delegate = self
the final step is just to call the method of the protocol like this..
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
To conclude if yo see this method in your class but you don't have access to the implementation of the protocol, you will ask yourself "where does this magic color coming from??" but as you saw it just comes from another class where a protocol belongs to, hope this helps.

How to pass instance of MKMapView to CLLocationManagerDelegate?

I have set my appDelegate class as the delegate for CLLocationManager. In the didUpdateLocations method of the delegate, I create a polyline. I add the polyline to the map view using [self.firstViewController.currentMap addOverlay:self.polyline level:MKOverlayLevelAboveRoads]. However, it has no effect on the actual instance of my map view because it thinks that self.firstViewController.currentMap is nil. Is there a way to somehow pass the instance of the map to didUpdateLocations so that it adds the overlay to the existing instance of the MKMapView?
You can't pass extra parameters in delegate methods. The method signatures of the delegate methods are fixed.
However, that's not the correct solution. It sounds like you got help in the comments that's enabled you to fix this though.

iOS: Creating a method that can be used by different objects?

I'm trying to create a method that can be called from any object that has a property backgroundColor. Should I subclass NSObject and add a class method or is there a different way to do something like this, that doesn't require adding a category for every object.
Something along the lines of:
[self.myLabel addAwesomeLayerWithSomeColor:(UIColor *)color];
[self.myView addAwesomeLayerWithSomeColor:(UIColor *)color];
[self.myButton addAwesomeLayerWithSomeColor:(UIColor *)color];
Looks like you want this method to be usable on views and subclasses of views. The correct thing to do would be to make a category on UIView. Then, all of these subclasses and any others will be able to use this method.

Inheritance: Restricting rather than extending? [duplicate]

This question already has answers here:
Is it possible to make the -init method private in Objective-C?
(9 answers)
how to block a superclass method to be called to a subclass
(5 answers)
Closed 9 years ago.
Suppose you have a UIView subclass. You define an init method "myInitWithFrame: ... andWhatNot:...". You know you won't be using the init method inherited from UIView ever and your custom init method does some vital custom initialising so that you want to force client classes to never use the inherited initWithFrame method.
Is it possible to hide the standard initWithFrame method that was inherited from UIView?
Actually, you can get compile-time warnings about calling a method on a subclass. Use the __attribute((deprecated)) attribute. If you want people to use -initWithPizza: instead of -initWithFrame:, do this:
#interface MyView : UIView
- (id)initWithPizza:(MyPizza *)pizza;
#end
#interface MyView (Deprecations)
- (id)initWithFrame:(CGRect)frame __attribute((deprecated("Use initWithPizza: instead")));
#end
Putting the -initWithFrame: declaration in a separate category is necessary to avoid Xcode complaining that you declared the method in the header but didn't implement it. Since you're just inheriting it from the superclass, that's fine; you don't have to implement it at all. But if you want to implement it to throw an exception, or call through to -initWithPizza: with a default argument, that's fine.
Of course, this won't stop UIKit from calling -initWithFrame: if it was already going to do so. But if you can guarantee that won't happen, then you're fine.
Actually, you CAN restrict with a subclass. You can override whichever methods you want to block in your subclass's .h file. You can make initWithFrame unavailable by placing the following in your .h file.
- (id) initWithFrame:(CGRect) frame __attribute__((unavailable("message")));
This will make the initWithFrame: method unavailable to anyone using your subclass.
To keep other code form calling this method, you can further restrict by putting this in your .m file.
- (id) initWithFrame:(CGRect) frame
{
return nil;
}
No. You can't prevent the users of your subclass from calling the methods of a superclass. You could override them and throw an exception inside, but that would just produce a broken subclass.
Remember that inheritance works as an "is a" extension, that is, instances of your subclasses should behave normally in any context that doesn't know about this particular subclass but knows about its superclass. It's only in places that have explicit knowledge about your subclass that you can benefit from adding extra initialization and other methods.
For example, UIKit has no knowledge of your subclass. So if you want to make your UIView subclass available from a NIB, you need to use the initialization methods that will be called by the NIB loading system, namely initWithCoder:. You can simply call your own initialization methods inside initWithCoder:. But if there are any additional parameters you would like to pass to the init method, you'll have to provide a way to configure them after initialization.

Calling the delegate methods

Still I couldn't understand completely how these delegate methods are getting called.
I have UIViewController,UITextFieldDelegate in one class which will call its delegate methods without specifying like textField.delegate = self;
But for some different purposes like UIWebViewDelegate we are supposed to enter like webView.delegate = self; and it seems like it is calling its delegate methods. Perfect.
But now I am facing a problem. I am using CLLocationManagerDelegate and also CALayer in same class. For both I am giving location.delegate =self; and layer.delegate =self; At some point both are conflicting each other and only one of the thing is working either CLLocationManagerDelegate or CALayer. The other thing is getting stopped. I don't why it so happens like this? Any reason? How can we overcome this. Even I planned to use some other frameWork, say UIWebView . I will face same problem for those delegate methods also. Can you tell me why it is working in that way ?
The classes that will call its delegates without you specifying them have default implementations, which means that they already know what to do, and will only change their behavior if you override these methods.
Setting 2 or more classes to the same delegate should not interfere with each other (unless for a very weird reason in where the method is named the same in both custom classes).
Your problem is most likely the fact that you havent implemented those methods or are using those classes wrong.
For example, Location manager requires you to create an instance, configure it and START running updates. The most common method for a delegate of this type is the "did update location" (or something like that). Which you have to implement if you want to be informed of every time a new location is received. Otherwise you have to read the location manually whenever you desire.
As a suggestion, every time you set a delegate for an object, you have to do the object.delegate = self; thing. And you probably noticed that you will get a warning until you specify in the header that it conforms to that protocol: for example.
Just control click the UITextFieldDelegate word.
Look for the methods under #required, THOSE you have to always implement. the #optional have default implementations so unless you wanna change the behavior its not needed to implement them.

Resources