Subclassing MKOVerlay View- canDrawMapRect not called - iphone

I am attempting to subclass MKOverlayView to create a custom overlay. I understand that in order to do this, one must override the following two methods
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context;
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale;
My question arrises from the latter method. For some reason, when I override it in my MKOverlayView subclass, it does not get called. According to documentation, it should be called before tiles are rendered and if it returns YES, then drawMapRect is called. I was hoping that someone could look at the following code and see if they can figure out why this method is not being called. Is it meant to be enabled/called manually somewhere?
Interestingly enough, drawMapRect does get called, it's only canDrawMapRect that does not. Am I misinterpreting the functionality of canDrawMapRect or is something wrong in my code?
HeatMapOverlay.h
#import <MapKit/MapKit.h>
#import <Foundation/Foundation.h>
#interface HeatMapOverlayView : MKOverlayView{
...variables...
}
#end
HeatMapOverlay.m
#import "HeatMapOverlayView.h"
#import <CoreGraphics/CoreGraphics.h>
#import <QuartzCore/QuartzCore.h>
#implementation HeatMapOverlayView
#synthesize points, heat, QualityIndex;
- (id)initWithOverlay:(id<MKOverlay>)overlay {
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale{
...complete check...
return NO;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext (CGContextRef)context{
...draw overlay...
}
Thank you!

Try changing this line:
self = [super init];
to this to use the proper initializer for an MKOverlayView:
self = [super initWithOverlay:overlay];

Related

Global Functions Objective C

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];

How to access a method in an object within another object, from the outside?

I am in ViewController, trying to access a method in object "cat" owned by object "backgroundpicture". ViewController has an instance of backgroundpicture.
The method/message in "cat.h":
#interface Cat : NSObject
-(BOOL)checkIfTouchHit:(float) xx :(float) yy;
#end
"Cat.m":
- (BOOL)checkIfTouchHit:(float) xx :(float) yy{
NSLog(#"Inside checkIfTouchHit");
return YES;
}
"BackGroundPicture.h":
#import "Cat.h"
#interface BackGroundPicture : NSObject
#property (strong) Cat * katt;
#end
"BackGroundPicture.m":
#implementation BackGroundPicture
#synthesize katt = _katt
#end
"ViewController.m":
#interface ViewController ()
#property (strong) BackGroundPicture * bakgrunnsbilde;
#end
#implementation BackGroundPicture
#synthesize bakgrunnsbilde = _bakgrunnsbilde;
- (void)viewDidLoad
{...
[[self.bakgrunnsbilde katt] checkIfTouchHit :(float)touchLocation.x :(float)touchLocation.y]
...}
The string inside the method "checkIfInside" in cat will not show up. I also tried
[_bakgrunnsbilde katt]...
but with the same lack of result, and I believe this is compiled the same way. I am wondering what I am missing here, and hope someone can help. Thanks :)
edit I forgot to add a few lines from my BackGroundPicture.m. It is a method run on start from the ViewDidLoad in ViewController. It is like this in BackGroundPicture.m:
- (void)createObjects {
Cat * katt = [[Cat alloc] init];
}
it is called from ViewController.m like so:
- (void)viewDidLoad
{
[_bakgrunnsbilde createObjects];
}
I know that this get executed. I hope this edit makes sense, my head is ruined after a long day :) Going to check back tomorrow morning.
It will work, but BackGroundPicture.m needs to allocate a cat first.
So in BackGroundPicture.m, do this:
- (id)init {
self = [super init];
if (self) {
_katt = [[Cat alloc] init];
}
return self;
}
In general, remember to allocate objects before you use them. You may also need to create a BackGroundPicture, too as Valentin points out. In viewDidLoad, do this:
bakgrunnsbilde = [[BackGroundPicture alloc] init];
As far as I can see you're accessing the method correctly. You could use the property, for readability sake (you also don't need the cast)
[self.bakgrunnsbilde.katt checkIfTouchHit:touchLocation.x :touchLocation.y]
, but your way of doing it should work as well.
You should check if your -viewDidLoad method gets called and if self.bakgrunnsbilde or self.bakgrunnsbilde.katt is not nil when -viewDidLoad gets called. One of this should get you on the right track.

Cant call instance methods from other classes

I hope you can help me with the following problem in Objective-C. I´ve been sitting around for two hours now, but I have no idea what´s wrong.
Here´s my code:
BMICalc.h:
#import <UIKit/UIKit.h>
#interface BMICalc : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
#property (strong, nonatomic) NSMutableArray *bmiArray;
-(int)bmiRows;
#end
BMICalc.m:
#import "BMICalc.h"
#implementation BMICalc
#synthesize bmiArray;
- (int) bmiRows
{
if (!bmiArray)
{
bmiArray = [[NSMutableArray alloc] init];
}
return [bmiArray count];
}
#end
Now I want to create a object of BMICalc in another class called BMIDiaryController:
BMIDiaryController.m:
#import "BMIDiaryController.h"
#import "BMICalc.h"
#interface BMIDiaryController ()
#end
#implementation BMIDiaryController
- (void)viewDidLoad
{
[super viewDidLoad];
BMICalc *bmiSender = [[BMICalc alloc] init];
int bmiVariable = [bmiSender bmiRows];
}
#end
So when I start the programme i get the following error:
"No visible #interface for 'BMICalc' declares the selector 'bmiRows'
I can´t call the method "bmiRows" with the object "bmiSender" (both of Class "BMICalc"
I hope you can help me with this. I searched and searched...I think it´s just a small thing, but I won´t see it...
Thank you and regards,
Stefan
Try creating a new project. Then add the BMICalc.m and BMICalc.h files. Try to instantiate your BMICalc object and call the bmiRows method from the appDelegate just to test it. There could be any number of things wrong in your main project that may be interfering with the class. At least doing this will confirm that you aren't crazy and that this code isn't the problem :)

protocol method is not being called by the delegate object

Another case of protocol method not being called - NO idea what am I doing wrong here...
Here is the code, omitting unnecessary info...
first header file: AccessNumber.h
#protocol AddItemDelegate <NSObject>
#required
- (void) processSuccessful: (BOOL)success;
#end
#interface AccessNumber : UIViewController <UITableViewDelegate, UITableViewDataSource, ABPeoplePickerNavigationControllerDelegate, UIAlertViewDelegate> {
id <AddItemDelegate> delegate;
}
#property (retain) id <AddItemDelegate> delegate;
#end
first .m file: AccessNumber.m - I am calling the protocol method from viewdidload just for testing purposes, it should basically get called from another method, but same thing for the sake of this convo (tried both of course)
#import "AccessNumber.h"
#import "History.h"
#synthesize delegate;
- (void)viewDidLoad
{
[super viewDidLoad];
....
[[self delegate] processSuccessful:YES];
}
second file header: History.h
#interface History : UIViewController <UITableViewDelegate, UITableViewDataSource, AddItemDelegate> {
....
}
method implementation in history.m
- (void) processSuccessful: (BOOL)success {
NSLog(#"SUCCESS");
}
Appreciate any help. Thanks!
In the code i don't see something like:
theAccessNumber.delegate = self;
You must set the History instance as the delegate property of the AccessNumber instance.
Regards.
The code seems a little bit funny but you are not telling your "AccessNumber" class who is his delegate, even though you are making the "History" class implement the protocol established by yourself (otherwise you would get a warning).
You have to set the delegate for the "AccessNumber" class like this when setting it up from within "AccessNumber.m":
self.delegate = historyInstance;
or like this when setting it up from within "History.m":
accessNumberInstance.delegate = self;
There are very vew situations where you should retain a delegate, normally your delagate will outlive the object. So change your property from retain to assign. And be sure you are setting the delegate. Where are you doing it? If your object really depends on it you should be passing it in the constructor (iniWithDelagate). Try doing a NSLog before calling the delagate method just to see if it isn't nil.

MKMapViewDelegate derived class and delegate assignment

This is probably more of an objective-c question over iOS but I've seen some example code similar to the following that I'd like to better understand.
#interface MyMapView : MKMapView <MKMapViewDelegate> {
// ivars specific to derived class
}
#property(nonatomic,assign) id<MKMapViewDelegate> delegate;
#end
#implementation MyMapView
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// initialize the ivars specific to this class
// Q1: Why invoke super on this delegate that's also a property of this class?
super.delegate = self;
zoomLevel = self.visibleMapRect.size.width * self.visibleMapRect.size.height;
}
return self;
}
#pragma mark - MKMapViewDelegate methods
// Q2: Why intercept these callbacks, only to invoke the delegate?
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
if( [delegate respondsToSelector:#selector(mapView:regionWillChangeAnimated:)] )
{
[delegate mapView:mapView regionWillChangeAnimated:animated];
}
}
#end
My two questions are:
1. Why would one invoke the super.delegate and also only declare the 'delegate' as a property?
2. Why intercept all of the delegate calls only to forward them back to the delegate?
I appreciate any insights.
Apple's documentation explicitly states that you should avoid subclass MKMapView:
http://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKMapView_Class/MKMapView/MKMapView.html#//apple_ref/doc/uid/TP40008205
Although you should not subclass the MKMapView class itself, you can
get information about the map view’s behavior by providing a delegate
object.
So i guess this delegate "forward" pattern is used to not break things.
I use a little different approach to subclass MKMapView. To minimize breakage i use two classes. One that subclass MKMapView and just override the init/dealloc method and assign/release the delegate property to a instance of the other class. The other class is a subclass of NSObject that implements the MKMapViewDelegate protocol and will be the one that does the real work.
MyMapView.h
#interface MyMapView : MKMapView
#end
MyMapView.m
// private map delegate class
#interface MapDelegate : NSObject <MKMapViewDelegate>
// instance is not alive longer then MKMapView so use assign to also solve
// problem with circular retain
#property(nonatomic, assign) MKMapView *mapView;
#end
#implementation MapDelegate
#synthesize mapView;
- (id)initWithMapView:(ReportsMapView *)aMapView {
self = [super init];
if (self == nil) {
return nil;
}
self.mapView = aMapView;
return self;
}
// MKMapViewDelegate methods and other stuff goes here
#end
#implementation MyMapView
- (id)init {
self = [super init];
if (self == nil) {
return nil;
}
// delegate is a assign property
self.delegate = [[MapDelegate alloc] initWithMapView:self];
return self;
}
- (void)dealloc {
((MapDelegate *)self.delegate).mapView = nil;
[self.delegate release];
self.delegate = nil;
[super dealloc];
}
#end
The mapView property for MapDelegate class is not strictly needed but is probably useful if want to do things to the map view that that is not a result of some MKMapViewDelegate method call, timers etc.
Why would one invoke the super.delegate and also only declare the 'delegate' as a property?
Ans. As you are making a custom mapview it is important to call the delegates too.We are invoking the super class delegate to send control from the custom Mapview.
Why intercept all of the delegate calls only to forward them back to the delegate?
Ans.At that line of code we are sending back the control to that delegate method declared in super class to do some useful thing.
Hope it will solve the query.