Following this tutorial on how to display XML latitude and longitude data as pins on iOS map kit:
http://highoncoding.com/Articles/805_Consuming_XML_Feed_and_Displaying_Public_Information_on_the_MapView_Control.aspx
The sample code provided compiles correctly and displays pins all across the united states. However when I tried to "port" the .xib into my app It pulls up my Mapview and the current users location, but it won't drop any pins/parse the data?
I'm on Day 2 now, its a bit discouraging.
Heres my .m and .h
EleventhViewController.h
// SlideMenu
//
// Created by Kyle Begeman on 1/13/13.
// Copyright (c) 2013 Indee Box LLC. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
//#interface EleventhViewController : NSObject <UIApplicationDelegate,MKMapViewDelegate,CLLocationManagerDelegate> {
#interface EleventhViewController : UIViewController <MKMapViewDelegate,CLLocationManagerDelegate,UIApplicationDelegate>
{
IBOutlet MKMapView *mapView;
NSMutableArray *greenCities;
CLLocationManager *locationManager;
}
//-(void) MKMapViewDelegate;
//-(void) CLLocationManagerDelegate;
//#property (nonatomic, weak) id<UIApplicationDelegate> delegate;
//#property (nonatomic, weak) id<MKMapViewDelegate> delegate;
//#property (nonatomic, weak) id<CLLocationManagerDelegate> delegate;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic,retain) IBOutlet MKMapView *mapView;
#property (nonatomic,retain) NSMutableArray *greenCities;
#property (strong, nonatomic) UIButton *menuBtn;
#property (strong, nonatomic) UIButton *searchBtn;
#end
Heres the .m
//
// EleventhViewController.m
// SlideMenu
//
// Created by Kyle Begeman on 1/13/13.
// Copyright (c) 2013 Indee Box LLC. All rights reserved.
//
#import "EleventhViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#import "GreenCitiesAppDelegate.h"
#import "GreenCitiesService.h"
#import "GreenCityAnnotation.h"
#import "GreenCityAnnotationView.h"
#import "GreenCity.h"
#interface EleventhViewController ()
//#interface EleventhViewController : UIViewController <MKMapViewDelegate>
#end
#implementation EleventhViewController
#synthesize window=_window,mapView,greenCities;
#synthesize menuBtn;
#synthesize searchBtn;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.mapView.delegate = self;
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.mapView setShowsUserLocation:YES];
GreenCitiesService *greenService = [[GreenCitiesService alloc] init];
self.greenCities = [greenService getGreenCities];
[self.window makeKeyAndVisible];
return YES;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.window.layer.shadowOpacity = 0.75f;
self.window.layer.shadowRadius = 10.0f;
self.window.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
self.menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
menuBtn.frame = CGRectMake(9, 23, 40, 30);
[menuBtn setBackgroundImage:[UIImage imageNamed:#"menuButton.png"] forState:UIControlStateNormal];
[menuBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:self.menuBtn];
//Top Main Menu Search Button
self.searchBtn = [UIButton buttonWithType:UIButtonTypeCustom];
searchBtn.frame = CGRectMake(275, 25, 40, 30);
[searchBtn setBackgroundImage:[UIImage imageNamed:#"searchButton.png"] forState:UIControlStateNormal];
[searchBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:self.searchBtn];
}
- (void)mapView:(MKMapView *)mv didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"didUpdateUserLocation fired!");
CLLocationCoordinate2D maxCoord = {-90.0f,-180.0f};
CLLocationCoordinate2D minCoord = {90.0f, 180.0f};
for(int i = 0; i<=[self.greenCities count] - 1;i++)
{
GreenCity *gCity = (GreenCity *) [self.greenCities objectAtIndex:i];
CLLocationCoordinate2D newCoord = { gCity.latitude, gCity.longitude };
if(gCity.longitude > maxCoord.longitude)
{
maxCoord.longitude = gCity.longitude;
}
if(gCity.latitude > maxCoord.latitude)
{
maxCoord.latitude = gCity.latitude;
}
if(gCity.longitude < minCoord.longitude)
{
minCoord.longitude = gCity.longitude;
}
if(gCity.latitude < minCoord.latitude)
{
minCoord.latitude = gCity.latitude;
}
GreenCityAnnotation *annotation = [[GreenCityAnnotation alloc] initWithCoordinate:newCoord title:gCity.name subTitle:gCity.rank];
[mv addAnnotation:annotation];
// [annotation release];
}
MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}};
region.center.longitude = (minCoord.longitude + maxCoord.longitude) / 2.0;
region.center.latitude = (minCoord.latitude + maxCoord.latitude) / 2.0;
// calculate the span
region.span.longitudeDelta = maxCoord.longitude - minCoord.longitude;
region.span.latitudeDelta = maxCoord.latitude - minCoord.latitude;
[self.mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)revealMenu:(id)sender
{
[self.slidingViewController anchorTopViewTo:ECRight];
}
#end
My Project is pretty simple, uses a lot of free source code so feel free to download what I've made up to this point, I'm pretty sure it would make a good template/starting base for a lot of you:
https://www.dropbox.com/s/8xxx08zyqpr9i8v/CDF.zip
The method didFinishLauching with options should only be used in the app delegate. You need to move the code from here into viewDidLoad and delete the didFinishLaunching method. Also delete the reference you have to the app delegate from the storyboard xib.
You really want to then set breakpoints in the app and work out where the data load is going wrong.
That fixed it! I moved every piece of executed code under the viewDidLoad! I feel like a noob (which I am) I would up vote you but I don't have enough rep yet. However I keep my connections to the app delegate I imported from the greencities .zip source. Thanks so much. This has however created a new bug in that I can't access my slider menu...fix one problem get another...I really appreciate the direction
Related
My problem is this, in the app when a user clicks somewhere not important an alertView is raised that's ok, I can find the call to that view, but then is showing again and again empty and I have placed breakpoint everywhere I see a call to any alert. But the ghost alert is not breaking anywhere I have no idea who is throwing it is just a sentient view.
Can you give some tips on how to pin point where is the view being called?
EDIT:
Code for the viewController:
#import <CoreLocation/CoreLocation.h>
#import "FormViewController.h"
#import "FormPageViewController.h"
#import "FormElement+UtilityMethods.h"
#import "UserBO.h"
#import "RecordBO.h"
#import "RecordAnswer.h"
#import "UserDefaultsUtilities.h"
#import "TimeTrackingUtilities.h"
#import "DxColors.h"
#import "EDQueueUtilities.h"
#import "GroupAnswerMetadata.h"
#import "RecordAnswer+UtilityMethods.h"
#import "Record+UtilityMethods.h"
#import "FormPageIndexViewController.h"
#import "ManagedObjectUtilities.h"
#import "EDQueue.h"
#import "EDQueueUtilities.h"
#import "DxAnswerObject.h"
#import "ImageAnswerMetadata.h"
#import "DateUtilities.h"
#import <ifaddrs.h>
#import "CarbonKit.h"
#define INITIAL_CONTROLLER_INDEX 0
#define FORM_RECORDS_TEMP_NAME #"<~TMP>"
#define TAG_RETURN_BUTTON 0
#define TAG_SAVE_BUTTON 1
#define TAG_SEND_BUTTON 2
typedef NS_ENUM(NSUInteger, AlertViewPurpose) {
ALERT_VIEW_FORM_NONE = 0,
ALERT_VIEW_FORM_SEND_SUCCESS = 1,
ALERT_VIEW_FORM_SEND_FAILURE = 2,
ALERT_VIEW_FORM_SAVE_PROMPT = 3,
ALERT_VIEW_FORM_FILE_NAME_PROMPT = 4,
ALERT_VIEW_FORM_ASYNC_SEND_SUCCESS = 5,
ALERT_VIEW_FORM_COULDNT_SEND = 6,
ALERT_VIEW_FORM_WANT_TO_SEND = 7,
ALERT_VIEW_FORM_SAVE_IN_CONTEXT_PROMPT = 8,
ALERT_VIEW_FORM_FILE_NAME_IN_CTXT_SAVE_PROMPT = 9,
ALERT_VIEW_FORM_REQUIRED_INTERNET_CONECTION = 10,
// Enumeration counter.
ALERT_VIEW_PURPOSE_COUNT
};
// Based on:
// Ref.: http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/
#interface FormViewController () <RecordBOProtocol, FieldElementProtocol,
CLLocationManagerDelegate, FormPageIndexProtocol,CarbonTabSwipeNavigationDelegate>
{
AlertViewPurpose _currentAlertViewPurpose;
CarbonTabSwipeNavigation *_carbonTabSwipeNavigation;
BOOL _unedited;
BOOL _formRecordNilAtStartUp;
BOOL _timestampTaken;
CLLocationManager *_locationManager;
CLLocation *_location;
NSDate *_timeSpentBaseTimestamp;
NSArray *_sortedPages;
NSUInteger _currentPageIndex;
NSString *formID;
NSArray *_pagesNames;
}
#property (weak, nonatomic) IBOutlet UILabel *lblFormTitle;
#property (weak, nonatomic) IBOutlet UIButton *btnSmallReturn;
#property (weak, nonatomic) IBOutlet UIButton *btnSmallSave;
#property (weak, nonatomic) IBOutlet UIButton *btnSmallSend;
#property (weak, nonatomic) IBOutlet UIButton *btnBigSend;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *btnReturn;
#property (strong, nonatomic) IBOutlet UIButton *lblBack;
#property (strong, nonatomic) IBOutlet UIButton *lblSave;
#end
#implementation FormViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
_currentAlertViewPurpose = ALERT_VIEW_FORM_NONE;
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self localizedButtons];
// Starting up location manager if form requires it.
// Ref.:
// https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/occ/instm/CLLocationManager/requestAlwaysAuthorization
if ([self.form.geolocationEnabled boolValue]) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
if ([CLLocationManager locationServicesEnabled]) {
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusNotDetermined) {
// Requesting authorization.
if ([CLLocationManager instancesRespondToSelector:#selector(requestWhenInUseAuthorization)]) {
#ifdef DEBUG_MODE
NSAssert(
[[[NSBundle mainBundle] infoDictionary] valueForKey:#"NSLocationWhenInUseUsageDescription"],
#"For iOS 8 and above, your app must have a value for NSLocationWhenInUseUsageDescription in its Info.plist");
#endif // DEBUG_MODE
[_locationManager requestWhenInUseAuthorization];
}
} else if (status == kCLAuthorizationStatusAuthorizedAlways ||
status == kCLAuthorizationStatusAuthorizedWhenInUse) {
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[_locationManager startUpdatingLocation];
}
}
}
self.lblFormTitle.text = self.form.name ;
// Saving whether self.formRecord was nil at beginning.
// Important for time spent tap calculations.
_formRecordNilAtStartUp = self.formRecord == nil;
[self setup];
//Take the time for counting
_timeSpentBaseTimestamp = [NSDate date];
_unedited = YES;
}
-(void)localizedButtons
{
[self.lblBack setTitle:NSLocalizedString(#"Back", #"Regresar") forState:UIControlStateNormal];
[self.lblSave setTitle:NSLocalizedString(#"Save", #"Guardar") forState:UIControlStateNormal];
[self.btnBigSend setTitle:NSLocalizedString(#"Send", #"Enviar") forState:UIControlStateNormal];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// Overriding from DxBaseViewController.
-(void)refresh
{
}
-(void)setup
{
// Obtaining sorted pages array.
_sortedPages = [[self.form.pages allObjects]
sortedArrayUsingComparator:^NSComparisonResult(Page *obj1, Page * obj2) {
return [obj1.pageNumber compare: obj2.pageNumber];
}];
//Adding toolBar
NSMutableArray *namesPages = [[NSMutableArray alloc]init];
for (Page *page in _sortedPages) {
NSString *namePage = page.name;
[namesPages addObject:namePage];
}
_pagesNames = [namesPages copy] ;
// Creating by default a record in case there's none.
if (self.formRecord == nil) {
self.formRecord = [Record createInContext:self.managedObjectContext];
// Filling in basic record information.
self.formRecord.name = FORM_RECORDS_TEMP_NAME;
self.formRecord.editable = self.form.editableRecords;
self.formRecord.dateLastSaved = self.formRecord.dateCreated = [NSDate date];
self.formRecord.syncStatusId = [NSNumber numberWithInt:SYNC_STATUS_NOT_SYNCED];
self.formRecord.user = [UserBO loggedInUser];
self.formRecord.form = self.form;
self.formRecord.formId = self.form.pkey;
self.formRecord.temporary = [NSNumber numberWithBool:YES];
self.formRecord.isBeingEdited = [NSNumber numberWithBool:YES];
// Committing record information as is. It will be removed if user doesn't
// want to save changes.
if (![Record commitChangesFromContext:self.managedObjectContext]) {
DebugLog(#"Temp form record couldn't be saved! Check!");
}
// Initializing page view controller.
_carbonTabSwipeNavigation =[[CarbonTabSwipeNavigation alloc] initWithItems:_pagesNames
delegate:self];
_carbonTabSwipeNavigation.toolbar.barTintColor = [DxColors colorWithHexRGB:NEW_FORMS_GREEN];
[_carbonTabSwipeNavigation setNormalColor:[UIColor whiteColor]];
[_carbonTabSwipeNavigation setIndicatorColor:[UIColor whiteColor]];
[_carbonTabSwipeNavigation setSelectedColor:[UIColor whiteColor]];
} else {
[self prepareControllerForEdition];
}
[_carbonTabSwipeNavigation insertIntoRootViewController:self];
self.pageViewController = _carbonTabSwipeNavigation.pageViewController;
}
- (UIViewController *)carbonTabSwipeNavigation:(CarbonTabSwipeNavigation *)carbontTabSwipeNavigation
viewControllerAtIndex:(NSUInteger)index {
_currentPageIndex = index;
// Create a new view controller and pass suitable data.
FormPageViewController *formPageViewController = [[FormPageViewController alloc] init];
formPageViewController.pageIndex = index;
formPageViewController.formPage = _sortedPages[index];
formPageViewController.managedObjectContext = self.managedObjectContext;
formPageViewController.formRecord = self.formRecord;
formPageViewController.observer = self;
formPageViewController.view.frame = CGRectMake(0,
0,
self.view.frame.size.width,
self.view.frame.size.height);
return formPageViewController;
}
#pragma mark - Button Actions (IBActions)
-(IBAction)send:(id)sender
{
_timer = [NSTimer scheduledTimerWithTimeInterval:0.001
target:self
selector:#selector(isAlertViewShowing:)
userInfo:nil
repeats:YES];
[self setButtonWithTag:self.btnBigSend.tag toHighlight:NO];
// Disabling button to avoid double submissions.
self.btnBigSend.enabled = NO;
// Show alert.
[self showAreYouReadyToSubmitFormMsg];
}
... can't paste it all
For testing only:
Subclass UIAlertView i.e. #interface MyAlertView : UIAlertView
Then replace all instances of UIAlertView from MyAlertView
i.e. MyAlertView *someAlert = [[MyAlertView alloc] init.......];
Then override
-(void)show {
[super show];
//Your breakpoint here
OR
NSLog([NSThread callStackSymbols]);
}
Check your viewcontroller that has an uialertviewdelegate.
Log your alertview.delegate
Check your super class of a viewcontroller that it doesn't call uialertviewdelegate function.
If it is an UIAlertController, check viewwillappear, viewdidappear, viewwilldisappear (super class too) and find out they don't call [alertview show]
Why you take enum for alertview ? just make instance of UIAlertView where it require's to show. you can make one method in which you can pass two string parameters alertview massage and title and method shows alertview with this title and massage.
You can catch the content of your AlertView, if it has no content at all, don't present it!
To do this check the message you are passing to the method that presents the alertView.
However, I can't seem to find your method showAreYouReadyToSubmitFormMsg.
I downloaded the latest Google Maps for iOS SDK, integrated with my project per the documentation. The map shows up fine. I have a marker who position I update every one sec in a thread. When the marker starts to update on the map, the map becomes very unresponsive. Zoom, pan etc take several seconds giving the perception that the map isn't working. Can some one please help?
A second question: When I don't update the UI, I am able to zoom, pan etc. At that time, the map I overlay'ed on the google maps resizes or moves around even though I am setting the coordinates where I want to anchor the image. How do I stop that and keep the map anchored?
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <GoogleMaps/GoogleMaps.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate, GMSIndoorDisplayDelegate, GMSMapViewDelegate>
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#property int counter;
#property (nonatomic, strong) GMSMapView *mapView;
#property (nonatomic, strong) GMSMarker *myMarker;
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic, strong) CLLocationCoordinate2D location;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:40.295210
longitude:-124.032841
zoom:10.5];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.mapView.delegate = self;
self.view = self.mapView;
[self.mapView setMapType:kGMSTypeHybrid];
/* Location Manager stuff */
}
- (void) viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self stopSending];
}
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self stopSending];
}
- (void) overlapMap {
self.mapView.mapType = kGMSTypeNormal;
CLLocationCoordinate2D southWest = CLLocationCoordinate2DMake(40.295048, -124.033110);
CLLocationCoordinate2D northEast = CLLocationCoordinate2DMake(40.295385, -124.032801);
GMSGroundOverlay *overlay = [self setGroundOverlayWithSouthWestCoordinate:southWest AndNorthEastCoordinate:northEast AndImage:[UIImage imageNamed:#"floorplan.png"]];
overlay.map = self.mapView;
[self.mapView animateToCameraPosition:[GMSCameraPosition
cameraWithLatitude:40.295210
longitude:-124.032951
zoom:30]];
[self.mapView setUserInteractionEnabled:true];
[self showMarkers];
}
- (void) showMarkers {
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateMarkerDetails) userInfo:nil repeats:YES];
}
- (void) updateMarkerDetails {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CLLocationCoordinate2D location = [self getLocation];
if (CLLocationCoordinate2DIsValid(location) {
self.myMarker = [GMSMarker markerWithPosition:location];
self.myMarker.map = self.mapView;
self.osLocation.map = self.mapView;
}
[self.mapView setSelectedMarker:self.myMarker];
/* some code with the marker title and subtitle*/
dispatch_async(dispatch_get_main_queue(), ^{
[self.myMarker setPosition:location];
});
});
}
- (void) clearMap {
self.myMarker.map = nil;
self.osLocation.map = nil;
[self.timer invalidate];
self.timer = nil;
}
- (CLLocationCoordinate2D) getLocation {
return self.location;
}
/*
Location Manager related code
Some other proprietary code
*/
#end
I did trial and error method of zeroing in on the problem and I found that when we use google maps, all and not some network related actions should be in background threads. I wasn't having all my network related actions in background threads. I changed things and the responsiveness is solved.
I am trying to display a UIImage as a overlay for a map-based iPad application. I attempted to follow the 4 steps to setting a custom overlay defined in Apple's documentation: define the overlay data object, define the object renderer, implement the map view in map view delegate, and add overlay data object to to map view. After attempting to do all these, there is no overlay when I run the simulator. Any advice would be fantastic. My code is as follows
ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "bjorkOverlay.h"
#import "bjorkOverlayRenderer.h"
#interface TUTViewController : UIViewController <MKMapViewDelegate>
{
CLLocationManager *locationManager;
CLLocation *location;
}
#property (strong, nonatomic) IBOutlet MKMapView *mapView;
#property(nonatomic) MKCoordinateRegion region;
#property (nonatomic, readonly) MKMapRect boundingMapRect;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic, readonly) CLLocationCoordinate2D bjorkOverlayCenterPoint;
#property (nonatomic, readonly) MKMapRect bjorkOverlayBoundingMapRect;
#end
ViewController.m
#import "TUTViewController.h"
#import "bjorkOverlay.h"
#import "bjorkOverlayRenderer.h"
#import MapKit;
#interface TUTViewController () <MKMapViewDelegate>
#end
#implementation TUTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];
_mapView.showsUserLocation = YES;
_mapView.delegate = self;
CLLocationCoordinate2D lowerLeftCoord = CLLocationCoordinate2DMake( 45.022943 ,-87.146606);
MKMapPoint lowerLeft = MKMapPointForCoordinate(lowerLeftCoord);
CLLocationCoordinate2D upperRightCoord = CLLocationCoordinate2DMake( 45.048513, -87.124765);
MKMapPoint upperRight = MKMapPointForCoordinate(upperRightCoord);
MKMapRect mapRect = MKMapRectMake(lowerLeft.x, upperRight.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);
[self.mapView setVisibleMapRect:mapRect animated:YES];
bjorkOverlay * mapOverlay = [[bjorkOverlay alloc] init];
[_mapView addOverlay:mapOverlay];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay: (id<MKOverlay>)overlay {
MKOverlayRenderer *mapOverlay = [[MKOverlayRenderer alloc] init];
return mapOverlay;
}
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
bjorkOverlay.h
#import <Foundation/Foundation.h>
#import MapKit;
#interface bjorkOverlay : NSObject <MKOverlay>
+ (id)overlayWithCoordinate:(CLLocationCoordinate2D)coordinate;
#property (nonatomic, assign) CLLocationCoordinate2D bjorkOverlayCenterPoint;
#property (nonatomic) MKMapRect bjorkOverlayBoundingMapRect;
#end
bjorkOverlay.m
#import "bjorkOverlay.h"
#import MapKit;
#implementation bjorkOverlay
+ (id)overlayWithCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius{
bjorkOverlay* overlay = [[bjorkOverlay alloc] init];
overlay.coordinate = coordinate;
return overlay;
}
-(MKMapRect)boundingMapRect{
CLLocationCoordinate2D lowerLeftCoord = CLLocationCoordinate2DMake( 45.022943 ,-87.146606);
MKMapPoint lowerLeft = MKMapPointForCoordinate(lowerLeftCoord);
CLLocationCoordinate2D upperRightCoord = CLLocationCoordinate2DMake( 45.048513, -87.124765);
MKMapPoint upperRight = MKMapPointForCoordinate(upperRightCoord);
MKMapRect mapRect = MKMapRectMake(lowerLeft.x, upperRight.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);
return mapRect;
}
- (CLLocationCoordinate2D)bjorkOverlayCenterPoint
{
CLLocationCoordinate2D coord1 = {
45.035728,-87.1356855
};
return coord1;
}
#end
bjorkOverlayRenderer.h
#import <MapKit/MapKit.h>
#interface bjorkOverlayRenderer : MKOverlayRenderer
#end
bjorkOverlayRender.m
#import "bjorkOverlayRenderer.h"
#implementation bjorkOverlayRenderer
- (void)drawMapRect:(MKMapRect)mapRect
zoomScale:(MKZoomScale)zoomScale
inContext:(CGContextRef)ctx
{
UIImage *image = [UIImage imageNamed:#"overlay.png"];
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGRect clipRect = [self rectForMapRect:mapRect];
CGContextAddRect(ctx, clipRect);
CGContextClip(ctx);
CGContextDrawImage(ctx, theRect, imageReference);
}
#end
Any advice would be great or if you have seen sample code for MKOverlayRenderer I would appreciate a link. Thanks
I've setup a delegate to take the old and new position of a gauge. However, I can't seem to get a response from the delegate. I could be missing something but I've done a bunch of research and it seems like everything is in order.
MeterView.h
#import <UIKit/UIKit.h>
#import "KTOneFingerRotationGestureRecognizer.h"
#protocol MeterViewDelegate;
#interface MeterView : UIView{
IBOutlet UIImageView *gauge;
IBOutlet UIImageView *needle;
float rotation, oldPos, newPos;
KTOneFingerRotationGestureRecognizer *rgest;
}
#property (nonatomic, weak) id<MeterViewDelegate> delegate;
- (IBAction)handleMovedNeedle;
#end
#protocol MeterViewDelegate <NSObject>
- (void)meterView:(MeterView*)view OldValue:(float)oldval NewValue:(float)newval;
#end
MeterView.m
#import "MeterView.h"
#import <QuartzCore/QuartzCore.h>
#implementation MeterView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
-(void)handleMovedNeedle{
if ([self.delegate respondsToSelector:#selector(meterView:OldValue:NewValue:)]) {
[self.delegate meterView:self OldValue:oldPos NewValue:newPos];
}
else{
NSLog(#"Delegate call FAIL, needle moved from %f, to %f", oldPos,newPos);
}
}
-(void)awakeFromNib{
gauge = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"gauge.png"]];
needle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"needle.png"]];
needle.frame = CGRectMake(0,gauge.frame.size.height-(needle.frame.size.height/2), gauge.frame.size.width, needle.frame.size.height);
[self addSubview:gauge];
[self addSubview:needle];
rotation = 0;
rgest = [[KTOneFingerRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
rgest.center = CGPointMake(CGRectGetMidX([needle bounds]) + needle.frame.origin.x, CGRectGetMidY([needle bounds]) + needle.frame.origin.y);
[self addGestureRecognizer:rgest];
}
- (void)rotate:(UIRotationGestureRecognizer *)recognizer {
switch (recognizer.state) {
case UIGestureRecognizerStateBegan: {
oldPos = ([(NSNumber *)[needle.layer valueForKeyPath:#"transform.rotation.z"] floatValue]/3.14)*100;
}
break;
case UIGestureRecognizerStateChanged: {
CGFloat angle = [(NSNumber *)[needle.layer valueForKeyPath:#"transform.rotation.z"] floatValue];
angle += [recognizer rotation];
if (angle >= 0 && angle <= M_PI) {
[needle setTransform:CGAffineTransformRotate([needle transform], [recognizer rotation])];
rotation += [recognizer rotation];
}
}
break;
case UIGestureRecognizerStateEnded: {
newPos = ([(NSNumber *)[needle.layer valueForKeyPath:#"transform.rotation.z"] floatValue]/3.14)*100;
[self handleMovedNeedle];
}
break;
default:
break;
}
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "MeterView.h"
#import "KTOneFingerRotationGestureRecognizer.h"
#interface ViewController : UIViewController<MeterViewDelegate>{
IBOutlet MeterView *secondMeter;
IBOutlet MeterView *thirdMeter;
}
#end
ViewController.m
#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
#define DEG2RAD(degrees) (degrees * 0.01745327) // degrees * pi over 180
#define RAD2DEG(radians) (radians * 57.2957795) // radians * 180 over pi
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
secondMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
secondMeter.delegate = self;
thirdMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
thirdMeter.delegate =self;
}
-(void)meterView:(MeterView *)view OldValue:(float)oldval NewValue:(float)newval{
NSLog(#"Delegate call SUCCESS, need moved from %f, to %f", oldval,newval);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This code:
secondMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
secondMeter.delegate = self;
thirdMeter = [[MeterView alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
thirdMeter.delegate =self;
creates 2 instances of your view, but it doesn't add them to a view, so they will never be seen.
So, you probably have some other view instances that are on view and don't have delegates, and these views which have delegates but aren't on display. Presumably from an XIB / storyboard as you have outlets.
Connect the views that are on display to the delegate using the outlets rather than creating new instances.
If you make the delegate property in the view an IBOutlet itself then you can connect the view controller as the delegate in the XIB / storyboard and you don't need to worry about the delegate in code at all...
Okay so i started learning UIDynamics and wanted to just work it out on small box.
I declared UIGravityBehaviour and UIDynamicsBehaviour in my ViewController.m and coded the UIView, but when i executed the code, it was not working.
But just as i declared them as #property in my .h file, the program was working completely fine.
What is the reason behind that?
What is the difference between declaring it as #property and without declaring it as #property?
Here are my files.
Before using #property
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView* box = [[UIView alloc]initWithFrame:CGRectMake(100, 50, 100, 100)];
box.backgroundColor = [UIColor blackColor];
[self.view addSubview:box];
UIDynamicAnimator* myAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIGravityBehavior* gravityBehaviour = [[UIGravityBehavior alloc] initWithItems:#[box]];
[myAnimator addBehavior: gravityBehaviour];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
After Declaring it as #property
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (strong,nonatomic) UIDynamicAnimator* myAnimator ;
#property (strong,nonatomic) UIGravityBehavior *gravityBehavior;
#property (strong,nonatomic) UICollisionBehavior *collisionBehavior ;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIView* box = [[UIView alloc]initWithFrame:CGRectMake(100, 50, 100, 100)];
box.backgroundColor = [UIColor blackColor];
[self.view addSubview:box];
self.myAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.gravityBehavior = [[UIGravityBehavior alloc] initWithItems:#[box]];
self.collisionBehavior = [[UICollisionBehavior alloc] initWithItems:#[box]];
self.collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
[self.myAnimator addBehavior:self.gravityBehavior];
[self.myAnimator addBehavior:self.collisionBehavior];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You don't have to move UIGravityBehavior to a property, only UIDynamicAnimator to make it work. However, it's probably a good idea anyway in case you want to remove specific gravity behaviours rather than all of them at once.
If you are using ARC:
The UIDynamicAnimator probably does not have a strong reference to the UIGravityBehavior. So after your viewDidLoad method returns, no one owns that UIGravityBehavior and ARC will make sure that that point it is released. When you make a property for it, your viewController owns it, so the UIGravityBehavior will survive until you viewController gets deallocated.