IOS 4.3.2 MapKit Annotations - ios

Hello we have an app that we are working on that is having some issuse getting the annotations to function correctly. The app builds and installs fine... there are about 50k pins being loaded from a database on the ipad...
The problem is that every pin will display the same annotation information when pressed... can't figure out how to have it reference the correct database field when a pin is pressed (the pins are all being displayed in the correct locations so we know it is referencing the database)
I imagine it's something here?
- (void) loadThePushPinInMap {
NSString * filename= [[NSBundle mainBundle] pathForResource:#"geocoded" ofType:#"csv"];
NSString *data = [NSString stringWithContentsOfFile:filename];
NSString *strippedPartOne = [data stringByReplacingOccurrencesOfString:#"\"" withString:#""];
NSArray *rows = [strippedPartOne componentsSeparatedByString:#"\r"];
int size = [rows count];
for (int i =0; i < size; i++) {
if(i==0)
continue;
// This is now the data being parse
NSArray * line = [[rows objectAtIndex:i] componentsSeparatedByString:#","];
double lat =[[[line objectAtIndex:5] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] doubleValue];
double lon =[[[line objectAtIndex:6] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] doubleValue];
//MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
//region.center.latitude = lat ;
//region.center.longitude = lon;
//region.span.longitudeDelta = 0.01f;
//region.span.latitudeDelta = 0.01f;
CLLocationCoordinate2D coordinate;
coordinate.latitude = lat;
coordinate.longitude = lon;
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
annotation.coordinate = coordinate;
annotation.title = [rows objectAtIndex:0];
annotation.subtitle = [rows objectAtIndex:4];
//[_mapView addAnnotation:annotation];
[self.mapView addAnnotation:annotation];
}
}
Here is the MKAnnotationsview code
#import <UIKit/UIKit.h>
#import <MapKit/MKFoundation.h>
// Post this notification to re-query callout information.
MK_EXTERN NSString * const MKAnnotationCalloutInfoDidChangeNotification;
#if (__IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED)
enum {
MKAnnotationViewDragStateNone = 0, // View is at rest, sitting on the map.
MKAnnotationViewDragStateStarting, // View is beginning to drag (e.g. pin lift)
MKAnnotationViewDragStateDragging, // View is dragging ("lift" animations are complete)
MKAnnotationViewDragStateCanceling, // View was not dragged and should return to it's starting position (e.g. pin drop)
MKAnnotationViewDragStateEnding // View was dragged, new coordinate is set and view should return to resting position (e.g. pin drop)
};
typedef NSUInteger MKAnnotationViewDragState;
#endif // #if (__IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED)
#class MKAnnotationViewInternal;
#protocol MKAnnotation;
MK_CLASS_AVAILABLE(NA, 3_0)
#interface MKAnnotationView : UIView
{
#private
MKAnnotationViewInternal *_internal;
}
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier;
#property (nonatomic, readonly) NSString *reuseIdentifier;
// Classes that override must call super.
- (void)prepareForReuse;
#property (nonatomic, retain) id <MKAnnotation> annotation;
#property (nonatomic, retain) UIImage *image;
// By default, the center of annotation view is placed over the coordinate of the annotation.
// centerOffset is the offset in screen points from the center of the annotion view.
#property (nonatomic) CGPoint centerOffset;
// calloutOffset is the offset in screen points from the top-middle of the annotation view, where the anchor of the callout should be shown.
#property (nonatomic) CGPoint calloutOffset;
// Defaults to YES. If NO, ignores touch events and subclasses may draw differently.
#property (nonatomic, getter=isEnabled) BOOL enabled;
// Defaults to NO. This gets set/cleared automatically when touch enters/exits during tracking and cleared on up.
#property (nonatomic, getter=isHighlighted) BOOL highlighted;
// Defaults to NO. Becomes YES when tapped on in the map view.
#property (nonatomic, getter=isSelected) BOOL selected;
- (void)setSelected:(BOOL)selected animated:(BOOL)animated;
// If YES, a standard callout bubble will be shown when the annotation is selected.
// The annotation must have a title for the callout to be shown.
#property (nonatomic) BOOL canShowCallout;
// The left accessory view to be used in the standard callout.
#property (retain, nonatomic) UIView *leftCalloutAccessoryView;
// The right accessory view to be used in the standard callout.
#property (retain, nonatomic) UIView *rightCalloutAccessoryView;
// If YES and the underlying id<MKAnnotation> responds to setCoordinate:,
// the user will be able to drag this annotation view around the map.
#property (nonatomic, getter=isDraggable) BOOL draggable NS_AVAILABLE(NA, 4_0);
// Automatically set to MKAnnotationViewDragStateStarting, Canceling, and Ending when necessary.
// Implementer is responsible for transitioning to Dragging and None states as appropriate.
#property (nonatomic) MKAnnotationViewDragState dragState NS_AVAILABLE(NA, 4_0);
// Developers targeting iOS 4.2 and after must use setDragState:animated: instead of setDragState:.
- (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated NS_AVAILABLE(NA, 4_2);
#end
Here is the Delegate.h codes.....
#import "MapinAppDelegate.h"
#implementation MapinAppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}
#end
Here are the Delegate.m codes....
#import <UIKit/UIKit.h>
#interface MapinAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end

Use CustomAnnotaion which is inherited by MKAnnotation only, in that class assign your own properties, like locationDetails, locationImage, etc.
To add this information, update your MKAnnotatinView, by implementing this delegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation
Example:
http://developer.apple.com/library/ios/#DOCUMENTATION/UserExperience/Conceptual/LocationAwarenessPG/AnnotatingMaps/AnnotatingMaps.html
http://www.highoncoding.com/Articles/805_Consuming_XML_Feed_and_Displaying_Public_Information_on_the_MapView_Control.aspx

Related

The current location is not visible on the map using MapKit

I want to show the user's current location on map using MapKit and everything goes ok but the user current location is not visible on the maps.
Here are the properties I have set for mapView:
Here is rest of the controller's code:
#import <MapKit/MapKit.h>
#import "ShowMarkerAndNavigateVC.h"
#interface ShowMarkerAndNavigateVC ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
CLLocationManager *mgr;
#implementation ShowMarkerAndNavigateVC
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"View loaded Successfully");
mgr = [[CLLocationManager alloc] init];
[mgr requestWhenInUseAuthorization];
NSLog(#"Reuquested always authorization");
}
- (IBAction)backButtonPressed:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
#end
I have also set the mapView delegate to the current controller as shown here:
The expected result is that it should show the user's current location.
The actual result is that it does not show location on the map as shown here:
First, I would suggest actually setting showsUserLocation property to YES in code.
Second, note that it is up to you to show the region where the user location actually is; for example:
- (void)mapView:(MKMapView *)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation {
CLLocationCoordinate2D coordinate = userLocation.location.coordinate;
MKCoordinateRegion reg =
MKCoordinateRegionMakeWithDistance(coordinate, 600, 600);
mapView.region = reg;
}
If you're using the simulator, you won't get the user's location, because the simulator doesn’t know its own location.
To do so, open the Debug menu of the Simulator and select Apple in the ***Location* sub-menu.
Hope this will help you.

IOS-Convert code-based interface to Storyboard based interface

I am referencing a IOS project that use code to create the interface rather than storyboard file.
But my project is using storyboard to build the user interface.
Right Now, all my file compile pretty well, but just do not run.
I keep getting "Thread 1:signal SIGABRT" error.
Below are my project file:
AppleDelegate.h
#import <UIKit/UIKit.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "DetectionViewModel.h"
#import "ViewController.h"
#import "RscMgr.h"
#interface AppDelegate ()
#end
#implementation AppDelegate{
#private
UIWindow* _mainWindow;
RscMgr* _serialManager;
ViewController* _viewController;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
_serialManager = [[RscMgr alloc] init];
DetectionViewModel* detectionViewModel = [[DetectionViewModel alloc] initWithSerialManager: _serialManager];
_viewController = [[ViewController alloc] initWithViewModel: detectionViewModel];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import <opencv2/videoio/cap_ios.h>
#import <opencv2/imgcodecs/ios.h>
using namespace cv;
#class DetectionViewModel;
#interface ViewController : UIViewController<CvVideoCameraDelegate>{
IBOutlet UIImageView* imageView;
// IBOutlet UIButton* startButton;
CvVideoCamera* videoCamera;
}
#property (nonatomic, retain) CvVideoCamera* videoCamera;
//- (IBAction)startButton:(id)sender;
-(instancetype)initWithViewModel:(DetectionViewModel*)viewModel;
#end
ViewController.m
#import "ViewController.h"
#import "DetectionViewModel.h"
#import "opencv2/videoio/cap_ios.h"
#import "opencv2/imgcodecs/ios.h"
#interface ViewController ()
#end
#implementation ViewController
{
#private
DetectionViewModel* _viewModel;
}
-(instancetype)initWithViewModel:(DetectionViewModel *)viewModel{
self = [super init];
if(self){
_viewModel = viewModel;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//serial Manager process
//
//camera
self.videoCamera = [[CvVideoCamera alloc] initWithParentView:imageView];
self.videoCamera.delegate =self;
self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;
self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPreset1920x1080;
// self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideo
self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
self.videoCamera.defaultFPS = 20;
self.videoCamera.grayscaleMode = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Protocol CvVideoCameraDelegate
#ifdef __cplusplus
- (void)processImage:(cv::Mat &)image{
Mat imageCopy,imageCopy2,imageCopy3,imageCopy4;
cvtColor(image, imageCopy, COLOR_BGRA2BGR);//cvtColor(image, image, COLOR_BGR2GRAY);
cvtColor(imageCopy, imageCopy2, COLOR_BGR2HSV);//bitwise_not(imageCopy, imageCopy);
GaussianBlur(imageCopy2, imageCopy3, cv::Size(5,5),0, 0);//smooth the image with gaussian blur
cv::inRange(imageCopy3, cv::Scalar(100,127.5,28.05,1), cv::Scalar(131,255,137.7,1), imageCopy4);//recognize blue
// cv::inRange(imageCopy3, cv::Scalar(0,0,0,0), cv::Scalar(180,255,40,0), imageCopy4);//recognize black in HSV
//other:threshold(imageCopy, image, 0, 255, 0);
/*****************************find the contour of the detected area abd draw it***********************************/
//2-D point to store countour
std::vector< std::vector<cv::Point>> contour1;
int erosionSize = 3;//do opening on the binary thresholded image
Mat erodeElement = getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(2*erosionSize+1,2* erosionSize+1), cv::Point(erosionSize,erosionSize));
erode(imageCopy4, imageCopy4, erodeElement);
dilate(imageCopy4, imageCopy4, erodeElement);
cv::findContours(imageCopy4, contour1, RETR_EXTERNAL, CHAIN_APPROX_NONE);//Acual line to find the contour
Scalar color1 = Scalar(50,50,50);//set the color used to draw the conotour
for(int i=0; i< contour1.size(); i++){//loop the contour to draw the contour
drawContours(image, contour1, i, color1);
}
/****************************find the contour of the detected area abd draw it***********************************/
/****************************Appproximate the contour to polygon && get bounded Rectangle and Circle*************/
std::vector<std::vector<cv::Point>> contours_poly(contour1.size());
std::vector<cv::Rect> boundedRect(contour1.size());
std::vector<cv::Point2f> circleCenter(contour1.size());
std::vector<float> circleRadius(contour1.size());
for (int i=0; i< contour1.size(); i++){
approxPolyDP(Mat(contour1[i]), contours_poly[i], 3, true);
boundedRect[i] = boundingRect(Mat(contours_poly[i]));
minEnclosingCircle((Mat)contours_poly[i], circleCenter[i], circleRadius[i]);
}
/*****************************draw the rectangle for detected area ***********************************************/
Scalar recColor = Scalar(121,200,60);
Scalar fontColor = Scalar(0,0,225);
int largestContourIndex=0;
for (int i=0; i<contour1.size(); i++){ //find the largest contour
if(boundedRect[i].area()> boundedRect[largestContourIndex].area())
largestContourIndex=i;
}
int j=largestContourIndex;
for (int i=0; i< 2/*contour1.size()*/; i++){ // draw all contours // draw Rect for the largest contour
if(contour1.size()>0){
if(boundedRect[j].area()>40){
rectangle(image, boundedRect[j].tl(), boundedRect[j].br(), recColor);
cv::Point fontPoint = boundedRect[j].tl();//show text at tr corner
putText(image, "Blue", fontPoint, FONT_HERSHEY_COMPLEX, 3, fontColor);
}
}
}
}
#endif
#pragma mark - UI Actions
- (IBAction)startVideoCamera:(UIBarButtonItem *)sender {
[self.videoCamera start];
}
- (IBAction)stopVideoCamera:(UIBarButtonItem *)sender {
[self.videoCamera stop];
}
- (IBAction)openWheel1:(UIBarButtonItem *)sender {
[_viewModel sendMessage:#"w1Open"];
}
- (IBAction)openWheel2:(UIBarButtonItem *)sender {
[_viewModel sendMessage:#"w2Open"];
}
#end
DetectionViewModel.h
#import <Foundation/Foundation.h>
#class RscMgr;
#interface DetectionViewModel : NSObject
-(instancetype)initWithSerialManager:(RscMgr*)serialManager;
-(void) sendMessage:(NSString*)message;
#end
DetectionViewModel.m
#import "DetectionViewModel.h"
#import "RscMgr.h"
#interface DetectionViewModel() <RscMgrDelegate>
#end
#implementation DetectionViewModel
{
#private
RscMgr* _serialManager;
}
-(instancetype)initWithSerialManager:(RscMgr* )serialManager{
self = [super init];
if(self){
_serialManager = serialManager;
[_serialManager setDelegate:self];
}
return self;
}
-(void)sendMessage:(NSString *)message{
[_serialManager writeString:message];
}
#pragma mark - Delegate
-(void)cableConnected:(NSString *)protocol{
}
-(void)cableDisconnected{
}
-(void)portStatusChanged{
}
-(void)readBytesAvailable:(UInt32)length{
}
#end
in Console:
I have following info:
2015-04-05 21:19:22.310 XRoverVideoProcessingTest[852:198728] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Could not find a storyboard named 'Main' in bundle NSBundle (loaded)'
* First throw call stack:
(0x184c2a530 0x195bac0e4 0x189a04484 0x1896c4590 0x1896c3728 0x1896c1f1c 0x18d0f1604 0x184be2d70 0x184be1e78 0x184be0078 0x184b0d1f4 0x1894a3020 0x18949e10c 0x10005fd68 0x19622aa08)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
And I did add the storyboard file name into the info list
It looks to me like perhaps the storyboard file was not added to the build target, so it can't be found at launch time

how to implement memoryReceiveWarning

i am in initial phase of development and i want to make sure i am in right direction with regards to memory management.
i have a view controller named LayoutViewController with xib.I have a custom ui-subclass with its xib named LayoutContainerView which basically contains a scrollview. I am using LayoutContainerView in LayoutViewController xib by IBOutlet.
I have an another UIView subclassed, which contains a view with background image, some labels and a transparent button with same frame as of viw.I am adding this custom controll in LayoutContainerView's scrollview.
my view controller .h looks like this:
#import <UIKit/UIKit.h>
#protocol LayoutVcRemovedProtocol;
extern const char* MyConstantKey;
#interface LayoutViewController : UIViewController
// public properties
#property (nonatomic, copy) NSString *databasePath;
#property (nonatomic, weak) id<LayoutVcRemovedProtocol> layoutVcRemovedProtocolDelegate;
#end
#protocol LayoutVcRemovedProtocol<NSObject>
-(void) layoutVcRemovedProtocolMethod;
#end
=========================
**some of relevant code of **implementation** file looks like this:**
//private stuffs goes here
const char* MyConstantKey = "MyConstantKey";
#interface LayoutViewController () <UIActionSheetDelegate, UIAlertViewDelegate>
#property(nonatomic, weak) IBOutlet LayoutContainerView *layoutContainerView;
#property(nonatomic, weak) IBOutlet UIButton *backbutton;
#property(nonatomic, weak) IBOutlet UILabel *layoutNameLabel;
#property (nonatomic, strong) UIView *baseView;
#property (nonatomic, strong) NSMutableArray *layoutModelArray;
-(IBAction)backButtonPressed;
#end
#implementation LayoutViewController
//my viewDidLoad and viewWillAppear look like this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self adjustLayoutContainerFrameAndSetDataBasePath];
}
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.layoutNameLabel.text = [Utils getLayoutName];
[self getLatestData];
}
-(void) getLatestData
{
[self setUpDataSource];
[self setUpComponentsOnLayoutScreen];
}
#pragma mark - datasource method
-(void)setUpDataSource
{`
self.layoutModelArray = (NSMutableArray *)[LAYOUTMODULE getAllLayoutData];
}`
-(void)setUpComponentsOnLayoutScreen
{`
for (int i = 0; i < self.layoutModelArray.count; i++)
{
Layout *layout = [self.layoutModelArray objectAtIndex:i];
[self drawViewWithLayoutObject:layout];
}
[self.layoutContainerView.scrollView adjustContentSize];
}
this is what i am trying to manage memory:
-(void) cleanLayoutModelArray
{
if (self.layoutModelArray != nil && self.layoutModelArray.count >0)
{
[self.layoutModelArray removeAllObjects];
}
}
-(void) cleanComponents
{
[self.layoutContainerView.scrollView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
}
//user events
-(void) placeOrderForLayout:(Layout *)layout
{
[DELEGATE showLandscapeLoading];
//web service COMMUNICATION HERE here
OrderModule *oModule = [OrderModule sharedModule];
NSDictionary *requestDictionary = [NSDictionary dictionaryWithObjectsAndKeys:oModule.currentOrder.mOrderId,#"order_id",oModule.currentOrder.mPosId,#"pos_id",[Utils currentDate],#"book_date", layout.componentId, #"component_id", nil];
BOOL status = [LAYOUTMODULE placeComponentOrderThroughAPI:requestDictionary];
if (status == TRUE)
{
[self performCleanUp];
[self getLatestData];
}
[DELEGATE stopLandscapeLoading];
}
help me or any suggestion for:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
what ever i try in memoryWarningDelegate view controller becomes black screen.
You've got a lot of #properties marked 'weak' in your code - when you mark things as weak, that means that something else is keeping track of whether it should still exist. Here you're doing it with IBOutlet items, which your controller should be keeping track, so they should be marked 'strong,' not weak. I'd review all your usage of 'weak' in this. Also refer to Apple's excellent doc on memory management. ARC will be handling most of your memory management for you. Usually, the only thing you need to do in didReceiveMemoryWarning, is to set to nil anything that's a large object, say a video or webpage you can reload if the user needs it again. Often, there's not much that you can free up at this time in your typical view. Note also that iOS devices have a fairly substantial memory footprint these days, so you should not worry about small data structures remaining resident in memory as long as they have the potential to be needed again. If you're having out of memory issues, I'd run with instruments and check for leaks.

Redrawing markers on a Route-me map

Working in iOS 6, I cannot seem to get the map view to update itself to show markers added or removed.
When the app opens, a number of markers are placed on the map. The user can then make choices that add new markers and/or remove existing markers. This uses the same method as when the RMMarkerManager is populated at viewWillLoad, and I can iterate through the markers in the RMMarkerManager and see that it has the new set of markers, but the map view never updates to show them.
I have tried [mapview setNeedsDisplay] with no effect.
Clearly, I'm missing something that causes the mapview to update the display of the markers, but I have not figured out what, despite lots of head-scratching and digging through documentations and posts.
I will appreciate any suggestions as to what I should change or add.
As requested, here is the appropriate code. I'll explain how it works.
In the viewController's createMarkers method, the markers are created by accessing a sqlite database. One marker is created for each record that I want displayed as a marker on the map. I then iterate through the array of markers, adding each to the mapView's marketManager (addMarker method). The method createMarkers is called in the viewController's viewWillLoad method, and works correctly: all markers are displayed.
When using the app, a user can select or de-select records in the database. Then the viewController receives a notification that the user has changed the selection, and calls its setMarkers method. The mapview's marketmanager gets a removeMarkers message, then the marker array is re-created; it now has markers reflecting the user's selections. But the map never updates the on-view markers. Markers removed by the user are not removed on the view; markers added by the user are not added.
After the update, I can iterate through mapview.markermanager.markers and see that it now contains the new markers. But they're never shown on the mapView.
Class: Marker, subclass of RMMarker.
Simply holds data about the marker to be displayed
Marker.h:
// Marker.h
#import <Foundation/Foundation.h>
#import "Location.h"
#import "RMMarker.h"
#interface Marker : RMMarker {
NSString *category_name;
NSString *name;
NSString *desc;
NSString *address;
NSString *png;
int marker_id;
float lat;
float longi;
CLLocationCoordinate2D node;
float label_x_offset;
float label_y_offset;
}
#property (nonatomic, strong) NSString *category_name;
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *desc;
#property (nonatomic, retain) NSString *address;
#property (nonatomic, retain) NSString *png;
#property (nonatomic) int marker_id;
#property (nonatomic) float lat;
#property (nonatomic) float longi;
#property (nonatomic) CLLocationCoordinate2D node;
#property (nonatomic) float label_x_offset;
#property (nonatomic) float label_y_offset;
#end
Class: Markers
Holds an NSMutableArray of Markers, which is populated from a sqlite database:
// Markers.m
#import "Markers.h"
#import "defs.h"
#import "FileLocator.h"
#import "Marker.h"
#implementation Markers
#synthesize markers;
-(NSMutableArray *) createMarkers {
markers = [[NSMutableArray alloc] init];
[self openDatabase];
NSString *query = [NSString stringWithFormat:#"SELECT categories.selected, categories.category_id, categories.png, places.name, address, description, latitude, longitude, place_id FROM places, categories WHERE (categories.selected = 1 AND places.category_id = categories.category_id);"];
debugPrintArgs(#"query: %#", query);
FMResultSet *rs = [db executeQuery:query];
while ([rs next]) {
Marker *marker = [[Marker alloc] init];
marker.marker_id = [rs intForColumn:#"place_id"];
marker.name = [rs stringForColumn:#"name"];
marker.address = [rs stringForColumn:#"address"];
marker.desc = [rs stringForColumn:#"description"];
marker.lat = [rs doubleForColumn:#"latitude"];
marker.longi = [rs doubleForColumn:#"longitude"];
marker.png = [rs stringForColumn:#"png"];
debugPrintArgs(#"%#, %#, %#, %f, %f", marker.name, marker.address, marker.description, marker.lat, marker.longi);
marker.label_y_offset = 150.0f;
marker.label_x_offset = 30.0f;
[markers addObject:marker];
}
[db close];
return markers;
}
#end
Methods in the viewcontroller:
setMarkers:
Iterates through the NSMUtableArray Markers, calling the method addMarker: for each marker in that array:
- (void) setMarkers {
// class Markers is essentially an NSMutableArray that holds instantiations of Marker - one for each marker to be displayed
// Markers is also responsible for populating itself from a sqlite database via the createMarkers method
Markers *markers = [[Markers alloc] init];
NSMutableArray *allMarkers = [markers createMarkers];
// allMarkers contains the markers to be displayed.
CLLocationCoordinate2D loc;
if ([allMarkers count] > 0) {
for (Marker *mrkr in allMarkers) {
loc.longitude = mrkr.longi;
loc.latitude = mrkr.lat ;
[self addMarker: mrkr at:loc withText:mrkr.name xOffset: mrkr.label_x_offset yOffset: mrkr.label_y_offset png: mrkr.png];
}
}
}
Also in the viewController: addMarker
And, finally, the addMarker method used to add a marker to the RMMarkerManager:
- (void) addMarker: (Marker *) marker at:(CLLocationCoordinate2D)loc withText:(NSString *)text xOffset: (float) x_offset yOffset:(float) y_offset png:(NSString *) png {
UIImage* markerImage = [UIImage imageNamed:png];
[marker replaceUIImage:markerImage anchorPoint:CGPointMake(0.38f, 1.08f)];
[viewMap.markerManager addMarker: marker AtLatLong: loc];
CGPoint position = CGPointMake( 0.0f, 0.0f);
[marker changeLabelUsingText: text position: position ];
}
The offending line here is in setMarkers:
Markers *markers = [[Markers alloc] init];
Making markers an instance variable and doing the alloc-init in the class's viewWillLoad method corrected the problem.
I wish I could explain this better, but I am unsure as to why this caused the problem. But, it's corrected now and I'll explore when I've got some time.

How to call a variable from another class

First off, do you guys know of any good tutorial sites or books to learn how to code for iOS6?
Now to the problem at hand, I have an AppDelegate class and a ViewController class.
I am using the AppDelegate class to find my current location and save it as an NSString.
I have a label in my ViewController class where I want to display my location.
In java I would usually just do something like this
label.text = AppDelegate.myLocationString;
But I am fairly new to objective c and I don't know how to do the equivalent. To be honest I'm not even sure if I am taking the correct approach for this language. Is there another way to approach this problem in objective c?
I've tried searching around for how to do it but I'm not even sure that I'm phrasing my searches correctly so I don't know if I'm searching in the right direction.
Any help that could be offered would be very much appreciated
My code as it is now:
AppDelegate.h
#import <UIKit/UIKit.h>
#import CoreLocation/CoreLocation.h
#class BIDViewController;
#interface BIDAppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) BIDViewController *viewController;
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (strong, nonatomic) NSString *myPosition;
#end
LocationManager class from AppDelegate.m
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15) {
//if it is within the last 15 seconds, use it. Else do nothing.
if (newLocation.horizontalAccuracy < 35.0) {
//location seems pretty accurate so we will use it
NSLog(#"latitude: %+.6f, longitude: %+.6f\n", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
NSLog(#"Horizontal accuracy: %f", newLocation.horizontalAccuracy);
int latDegrees = newLocation.coordinate.latitude;
int lonDegrees = newLocation.coordinate.longitude;
double latDecimal = fabs(newLocation.coordinate.latitude - latDegrees);
double lonDecimal = fabs(newLocation.coordinate.longitude - lonDegrees);
int latMinutes = latDecimal * 60;
int lonMinutes = lonDecimal * 60;
double latSeconds = ((latDecimal * 3600) - (latMinutes * 60));
double lonSeconds = ((lonDecimal * 3600) - (lonMinutes * 60));
_myPosition = [NSString stringWithFormat:#"Lat: %d, %d, %1.4f, Lon: %d, %d, %1.4f", latDegrees, latMinutes, latSeconds, lonDegrees, lonMinutes, lonSeconds];
}
}
}
ViewController.h
#import <UIKit/UIKit.h>
#interface BIDViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *positionLabel;
#end
ViewController.m
#import "BIDViewController.h"
#import "BIDAppDelegate.h"
#interface BIDViewController ()
#end
#implementation BIDViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//I have tried setting the label's text here but to no avail so far, I have been
//able to set it as "blah" with the following line:
//
// positionLabel.text = #"blah";
//
//and I have tried things such as the following to populate the label with the
//myPosition variable:
//
// positionLabel.text = _myPosition;
// or
// positionLabel.text = AppDelegate._myPosition;
}
- (void)viewDidUnload
{
[self setPositionLabel:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
To reference the App Delegate from your view controller, first import its definition (which you've ready done):
#import "BIDAppDelegate.h"
and then in code get the delegate:
BIDAppDelegate *appDelegate = (BIDAppDelegate *)[[UIApplication sharedApplication] delegate];
and then get the location from the delegate:
CLLocation *location = appDelegate.locationManager.location;
and then call whatever method you like on the location object:
NSString *descr = location.description;
Or get the pre-calculated position with:
NSString *position = appDelegate.myPosition;
In your ViewController
BIDAppDelegate *appDelegate = (BIDAppDelegate *)[UIApplication sharedApplication].delegate;
[positionLabel setText:appDelegate.myPosition];
How to call a variable from another class?
Assume you are in ClassB
ClassA *aObj=... ; //create an object of ClassA
aObj.propertyName=...;//set the property or ivar
NSString *string=aObj.propertyName;//retrieve it
do you guys know of any good tutorial sites or books to learn how to
code for iOS6?
http://www.lynda.com/Apple-training-tutorials/106-0.html
http://www.raywenderlich.com/tutorials

Resources