I'm following the MVCS paradigm for saving and then loading instances of data objects in a Test app related to updating mapping data.
BNRMapPoint.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface BNRMapPoint : NSObject<MKAnnotation, NSCoding>
{
double latitude;
double longitude;
#public NSArray *mapPoints;
}
-(id) initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subTitle:(NSString *)st;
//this is required property in MKAnnotation Protocol
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
//this is an optional property in MKAnnotation Protocol
#property (nonatomic, copy) NSString *title;
//this is an optional property in MKAnnotation Protocol
#property (nonatomic,readonly,copy) NSString *subTitle;
#end
BNRMapPoint.m (Model)
#import "BNRMapPoint.h"
#implementation BNRMapPoint
#synthesize coordinate=_coordinate;
#synthesize title=_title;
#synthesize subtitle=_subtitle;
-(void)encodeWithCoder:(NSCoder *)aCoder{
latitude = self.coordinate.latitude;
longitude = self.coordinate.longitude;
[aCoder encodeObject:self.title forKey:#"title"];
[aCoder encodeObject:_subTitle forKey:#"subTitle"];
[aCoder encodeDouble: latitude forKey:#"latitude"];
[aCoder encodeDouble:longitude forKey:#"longitude"];
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if (self= [super init]) {
[self setTitle:[aDecoder decodeObjectForKey:#"title"]];
self->_subTitle= [aDecoder decodeObjectForKey:#"subTitle"];
latitude= [aDecoder decodeDoubleForKey:#"latitude"];
longitude= [aDecoder decodeDoubleForKey:#"longitude"];
}
return self;
}
-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t subTitle:(NSString *)st{
if (self= [super init]) {
self.coordinate=c;
self.title=t;
_subtitle=st;
}
return self;
}
-(id) init{
return [self initWithCoordinate:CLLocationCoordinate2DMake(43.07, -89.32) title:#"Hometown" subTitle:self.subtitle];
}
#end
WhereamiViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#import "BNRMapPoint.h"
#import "RootObject.h"
#interface WhereamiViewController : UIViewController<CLLocationManagerDelegate,MKMapViewDelegate,UITextFieldDelegate>
{
#public RootObject *rootObj;
CLLocationManager *locationManager;
IBOutlet MKMapView *worldView;
IBOutlet UIActivityIndicatorView *activityIndicator;
IBOutlet UITextField *locationTitleField;
}
-(IBAction)buttonDidGetPressed:(id)sender;
-(BOOL)textFieldShouldReturn:(UITextField *)textField;
-(void)findLocation;
-(void)foundLocation:(CLLocation *)loc;
#end
WhereamiViewController.m (ViewController)
#import "WhereamiViewController.h"
#interface WhereamiViewController ()
#end
#implementation WhereamiViewController
-(IBAction)buttonDidGetPressed:(UISegmentedControl *)sender{//Silver challenge
NSLog(#"%#",NSStringFromSelector(_cmd));
if([sender selectedSegmentIndex]==0){
[worldView setMapType:MKMapTypeStandard];
}
else if([sender selectedSegmentIndex]==1){
[worldView setMapType:MKMapTypeHybrid];
}
else if([sender selectedSegmentIndex]==2){
[worldView setMapType:MKMapTypeSatellite];
}
}
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
NSLog(#"%#", NSStringFromSelector(_cmd));
if (self=[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
rootObj= [[RootObject alloc] init];
locationManager= [[CLLocationManager alloc] init];
[locationManager setDelegate:self];//self is Whereamicontroller. The delegate pointer is of type id<CLLocationManagerDelegate> and is an ivar of CLLocationManager.
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
}
NSLog(#"test");
return self;
}
-(void) viewDidLoad{
// [worldView setMapType:MKMapTypeSatellite]; Bronze challenge
[worldView setShowsUserLocation:YES];
}
-(void)findLocation{
NSLog(#"%#",NSStringFromSelector(_cmd));
[locationManager startUpdatingLocation];//This calls locationManager:didUpdateLocations:
NSLog(#"location updated");
[activityIndicator startAnimating];
[locationTitleField setHidden:YES];
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
NSLog(#"%#",NSStringFromSelector(_cmd));
[self findLocation];
[textField resignFirstResponder];
return YES;
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
NSLog(#"%#",NSStringFromSelector(_cmd));
CLLocationCoordinate2D centerCoordinate= [[userLocation location] coordinate]; //get the coordinate of current location.
MKCoordinateSpan span= MKCoordinateSpanMake(250, 250);//Structure members
MKCoordinateRegion mapPortionToDisplay= MKCoordinateRegionMakeWithDistance(centerCoordinate, span.latitudeDelta, span.longitudeDelta);//span.latitudeDelta=250 and span.longitudeDelta=250
[worldView setRegion:mapPortionToDisplay animated:YES];
// [worldView setRegion:mapPortionToDisplay];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading{
NSLog(#"%#",NSStringFromSelector(_cmd));
NSLog(#"Heading %#",newHeading);
}
-(void)foundLocation:(CLLocation *)loc{
NSLog(#"%#",NSStringFromSelector(_cmd));
CLLocationCoordinate2D coord= [loc coordinate];
NSDateFormatter *formatter= [[NSDateFormatter alloc] init];
NSDate *currentDate= [[NSDate alloc] init];
[formatter setDefaultDate:currentDate];
BNRMapPoint *bmp= [[BNRMapPoint alloc] initWithCoordinate:coord title:[locationTitleField text] subTitle:[[formatter defaultDate] description]];
[rootObj.mapPoints addObject:bmp];
[worldView addAnnotation:bmp];
MKCoordinateRegion region= MKCoordinateRegionMakeWithDistance(coord,250,250);
[worldView setRegion:region animated:YES];
//RESET the UI
[locationTitleField setText:#" "];
[activityIndicator stopAnimating];
[locationTitleField setHidden:NO];
[locationManager stopUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{ //CLLocationManagerDelegate method implementation
NSLog(#"%#", NSStringFromSelector(_cmd));
// NSTimeInterval t0=[[locations lastObject] timeIntervalSinceNow];
NSLog(#"%#",(CLLocation *)[locations lastObject]);
NSTimeInterval t= [[(CLLocation *)[locations lastObject] timestamp] timeIntervalSinceNow];
if (t<-180) {
return; //No op
}
[self foundLocation:[locations lastObject]];
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"Could not find location: %#",error);//CLLocationManagerDelegate method implementation
}
#end
RootObject.h
#import <Foundation/Foundation.h>
#interface RootObject : NSObject
#property NSMutableArray *mapPoints;
-(BOOL)saveChanges;
-(NSString *)dataObjectArchivePath;
#end
RootObject.m (Store)
#import "RootObject.h"
#implementation RootObject
#synthesize mapPoints;
-(NSString *)dataObjectArchivePath{
NSArray *documentDirectories= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory= [documentDirectories objectAtIndex:0];
NSString *finalPath= [documentDirectory stringByAppendingPathComponent:#"items.archive"];
return finalPath;
}
-(BOOL)saveChanges{
NSString *path= [self dataObjectArchivePath];
return [NSKeyedArchiver archiveRootObject:self.mapPoints toFile:path];writing to the file items.archive
}
-(id)init{
if (self=[super init]) {
NSString *path= [self dataObjectArchivePath];
self.mapPoints= [NSKeyedUnarchiver unarchiveObjectWithFile:path];//reading from the file items.archive
if (!self.mapPoints) {
self.mapPoints= [[NSMutableArray alloc] init];
}
}
return self;
}
#end
AppDelegate.m
- (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.
NSLog(#"%#",NSStringFromSelector(_cmd));
BOOL success= [[BNRItemStore sharedStore] saveChanges];
if (success) {
NSLog(#"Saved all of the BNRItems");
}
else{
NSLog(#"Could not save any of the BNRItems");
}
}
In the above code, the saveChanges method is called from application: didEnterBackground:. So i haven't made a singleton object for the Store (RootObject). But i instantiated it in the designated initializer of viewController. The data to be archived is BNRMapPoint objects. On the entering background state, the code did save the objects successfully. However after the relaunching the app, the initWithCoder is where its getting stuck. The app crashes when it comes to reading the previously saved MapPoint objects. Pls help.. I've checked almost possible. Don't know what to do. I'm stuck.
So the problem is that you have:
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
And you are trying to use setter on read only property:
self.coordinate=c;
This is why it says that unrecognized selector is send - becuase it's readonly so setter doesn't exists. Using property this was is the same as calling:
[self setCoordinate:c]
Just make property assignable
Related
//ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate,MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet UILabel *addresslbl;
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
//Viewcontroller.m
#import "ViewController.h"
#interface ViewController ()
{
CLLocationManager *locationManager;
CLLocationCoordinate2D updateLocation;
NSString *strAddress;
CLGeocoder *geocoder;
}
#end
#implementation ViewController
#define AzaveaCoordinate CLLocationCoordinate2DMake(19.167391, 73.247686)
- (void)viewDidLoad {
[super viewDidLoad];
[_mapView setRegion:MKCoordinateRegionMake(AzaveaCoordinate, MKCoordinateSpanMake(0.010, 0.010)) animated:YES];
geocoder = [[CLGeocoder alloc]init];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager requestWhenInUseAuthorization];
self.mapView.delegate = self;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
CLLocation *location = [[CLLocation alloc]initWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
[self geocode:location];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation
{
CLLocation *currentLocation = newLocation;
self.mapView.centerCoordinate = currentLocation.coordinate;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(currentLocation.coordinate,1500,1500);
[self.mapView setRegion: region animated:true];
[self geocode:currentLocation];
}
-(void)geocode:(CLLocation *)location
{
// geocoder = [[CLGeocoder alloc]init];
[geocoder cancelGeocode];
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *data, NSError *error)
{
CLPlacemark *placemark = [data lastObject];
NSDictionary * addressDict = placemark.addressDictionary;
NSArray * addressList = addressDict[#"FormattedAddressLines"];
NSString * address = [NSString stringWithFormat:#"%#,%#,%#",addressList[0],addressList[1],addressList[2]];
NSLog(#" Address is :%#",address);
self.addresslbl.text = address;
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is the moveable map code like ola and uber. Means when i move the map, at that time the map pin is noted, the noted pin is given me address of the that particular area like city, state, pincode etc in label, but i want only the longitude, latitude value of this address in label.
so please help me about this code. How can i get the longitude latitude value in ?
Assuming that the label that you want to is self.addresslbl, change this method:
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
CLLocation *location = [[CLLocation alloc]initWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
[self geocode:location];
}
To:
-(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
self.addresslbl.text = [NSString stringWithFormat:#"%f, %f", mapView.centerCoordinate.longitude, mapView.centerCoordinate.latitude];
}
I'm trying to follow this tutorial:
http://www.appcoda.com/how-to-get-current-location-iphone-user/
Everything is fine till I add this line:
locationManager = [[CLLocationManager alloc] init];
Then I get the error.
I also get errors for these lines: (Xcode suggests I use "_LongitudeLabel"?
if (currentLocation != nil) {
longitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
latitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
Any idea what's wrong? Does the tutorial have errors or have I done something wrong?
Thanks!
This is ViewController.m file:
#import "ViewController.h"
#implementation MyLocationViewController {
CLLocationManager *locationManager;
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
locationManager = [[CLLocationManager alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)getCurrentLocation:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
longitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
latitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
#end
This is ViewController.h file:
// ViewController.h
// MyLocationDemo
//
// Created by Ian Nicoll on 12/11/14.
// Copyright (c) 2014 Ian Nicoll. All rights reserved.
//
#import <CoreLocation/CoreLocation.h>
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *LatitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *LongitudeLabel;
#property (weak, nonatomic) IBOutlet UILabel *addressLabel;
- (IBAction)getCurrentLocation:(id)sender;
#end
#interface MyLocationViewController : UIViewController <CLLocationManagerDelegate>
#end
The first issue is an error on your part. You declared locationManager in MyLocationViewController but try to initialize it in the viewDidLoad of ViewController, where it of course does not exist.
The second issue is an issue with the instructions. When you declare an #property, the default behavior is to create an instance variable with an underscore in front of it.
So #property (weak, nonatomic) IBOutlet UILabel *LatitudeLabel; can be accessed as self.latitudeLabel (which goes through the setter/getter) or just _latitudeLabel which accesses the ivar directly. The latter is probably what you want.
Ok so the build now is Succeeded (though I'm not 100& sure I got things right) but now I get a warning for this line: locationManager.delegate = self; - Assigning to 'id'from incompatible type 'ViewControler *const_strong'
Would you know how to fix this warning?
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController {
CLLocationManager *locationManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
locationManager = [[CLLocationManager alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)getCurrentLocation:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
_LongitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
_LatitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
#end
I'm trying to save the name of a button using a singleton so that the name can be accessed in another view to play a video with the same name. However, I'm getting the error: SIGABRT. I don't really see what's wrong with my code. Any ideas?
#import "List.h"
#import "MyManager.h"
#import "Video.h"
#implementation ExerciseList
-(IBAction) goToVideo:(UIButton *) sender{
MyManager *sharedManager = [MyManager sharedManager];
sharedManager.vidName = [[sender titleLabel] text];
Video *videoGo = [[Video alloc] initWithNibName: #"Video" bundle: nil];
[self.navigationController pushViewController: videoGo animated: YES];
[videoGo release];
}
Here is my .h and .m for MyManager:
#import <foundation/Foundation.h>
#interface MyManager : NSObject {
NSMutableArray *workouts;
NSString *vidName;
}
#property (nonatomic, retain) NSMutableArray *workouts;
#property (nonatomic, retain) NSString *vidName;
+ (id)sharedManager;
#end
#import "MyManager.h"
static MyManager *sharedMyManager = nil;
#implementation MyManager
#synthesize workouts;
#synthesize vidName;
#pragma mark Singleton Methods
+ (id)sharedManager {
#synchronized(self) {
if (sharedMyManager == nil)
sharedMyManager = [[self alloc] init];
}
return sharedMyManager;
}
- (id)init {
if ((self = [super init])) {
workouts = [[NSMutableArray alloc] init];
vidName = [[NSString alloc] init];
}
return self;
}
-(void) dealloc{
self.workouts = nil;
self.vidName = nil;
[super dealloc];
}
#end
You should access the title of the button
sharedManger.vidName = [sender currentTitle];
However you are not using ARC so also check where your vidName property is retain or copy.
if it is not retain or copy then you can use this code also
if(sharedManger.vidname != nil){
[sharedManger.vidName release];
sharedManger.vidName = nil;
}
sharedManger.vidName = [[sender currentTitle] retain];
In few words, my application is doing that :
1) My main view (RootViewController) has a buton when I tap on it, it displays the player (PlayerViewController) :
2) In my Player, I initialize the video I want to play
-> It's working good, my movie is display
My problem :
When I go back to my main view :
And I tap again on the button, I get a *Program received signal: “EXC_BAD_ACCESS”.*
If I comment self.player.contentURL = [self movieURL]; it's working, but when I let it, iI have this problem.
I read that it's due to null pointer or memory problem but I don't understand why it's working the first time and not the second time. I release my object in dealloc method.
Thanks for your help !
Bruno.
Here is my code :
Root View Controller
RootViewController.h
#import <UIKit/UIKit.h>
#import "PlayerViewController.h"
#interface RootViewController : UIViewController {
IBOutlet UIButton * myButton;
}
#property (nonatomic,retain) IBOutlet UIButton * myButton;
-(IBAction)displayPlayer:(id)sender;
- (void) returnToRoot: (PlayerViewController *) controller;
#end
RootViewController.m
#import "RootViewController.h"
#implementation RootViewController
#synthesize myButton;
-(IBAction)displayPlayer:(id)sender
{
PlayerViewController *playerViewController = [[PlayerViewController alloc] initWithNibName:#"PlayerViewController" bundle:nil];
playerViewController.delegate = self;
playerViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController: playerViewController animated: YES];
[playerViewController release];
}
- (void) returnToRoot: (PlayerViewController *) controller
{
[self dismissModalViewControllerAnimated: YES];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[super dealloc];
}
#end
Player View Controller
PlayerViewController.h
#import <UIKit/UIKit.h>
#import <MediaPlayer/MPMoviePlayerController.h>
#protocol PlayerViewControllerDelegate;
#interface PlayerViewController : UIViewController {
UIView *viewForMovie;
MPMoviePlayerController *player;
}
#property (nonatomic, assign) id <PlayerViewControllerDelegate> delegate;
#property (nonatomic, retain) IBOutlet UIView *viewForMovie;
#property (nonatomic, retain) MPMoviePlayerController *player;
- (NSURL *)movieURL;
-(IBAction)goBackToRoot:(id)sender;
#end
#protocol PlayerViewControllerDelegate
- (void) returnToRoot: (PlayerViewController *) controller;
#end
PlayerViewController.m
#import "PlayerViewController.h"
#implementation PlayerViewController
#synthesize player;
#synthesize viewForMovie;
#synthesize delegate;
- (void)dealloc {
[super dealloc];
[player release];
[viewForMovie release];
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"viewDidLoad");
self.player = [[MPMoviePlayerController alloc] init];
[self.player autorelease];
self.player.view.frame = self.viewForMovie.bounds;
self.player.view.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.viewForMovie addSubview:player.view];
self.player.contentURL = [self movieURL];
[self.player play];
}
-(NSURL *)movieURL
{
NSBundle *bundle = [NSBundle mainBundle];
NSString *moviePath =
[bundle
pathForResource:#"myVideo"
ofType:#"mp4"];
if (moviePath) {
return [NSURL fileURLWithPath:moviePath];
} else {
return nil;
}
}
-(IBAction)goBackToRoot:(id)sender{
[self.delegate returnToRoot: self];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
#end
Problem
The second time I call "displayPlayer" I had the EXC_BAD_ACCESS
I solved it !!!
I look on the MPMoviePlayerController to see what kind of variable is contentURL
(NSURL *)contentURL
It means I have also to liberate it.
I do that in my dealloc method putting a nil value:
-(void) dealloc {
[super dealloc];
self.player.contentURL = nil;
[player release];
[viewForMovie release];
}
If I comment self.player.contentURL =
[self movieURL]; it's working, but
when I let it, iI have this problem.
In that case, how is contentURL declared? Does the #property definition include copy or retain?
I'm developing an iphone app using mapkit and CLLocationManager.
I put lots of MKPinAnnotationView on map (about 100) and I want to update all callout's subtitle whith user distance when I receive it.
How to do it ?
Thanks
I try this to update subtitle callout with new location but it didn't work well.
In my MyAppDelegate.h
extern NSString * const GMAP_USERLOCATION_CHANGED;
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
CLLocationManager *locationManager;
CLLocation *userLocation;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) CLLocation *userLocation;
#end
In my MyAppDelegate.m
#implementation MyAppDelegate
NSString * const GMAP_USERLOCATION_CHANGED = #"gMapUserLocationChanged";
#synthesize locationManager, userLocation;
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
userLocation = nil;
[[self locationManager] startUpdatingLocation];
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
}
#pragma mark -
#pragma mark Core Location delegate
- (CLLocationManager *)locationManager
{
if (locationManager != nil)
{
return locationManager;
}
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
return locationManager;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
self.userLocation = newLocation;
// send notification to defaulcenter
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:GMAP_USERLOCATION_CHANGED object:self.userLocation];
}
- (void)dealloc {
[window release];
[locationManager release];
[userLocation release];
[super dealloc];
}
#end
I made a customAnnotationView named MyAnnotation.
in MyAnnotation.h :
#interface MyAnnotation : MKPinAnnotationView<MKAnnotation>
{
double longitude;
double latitude;
NSString *title;
NSString *subtitle;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *subtitle;
#property double longitude;
#property double latitude;
#end
in MyAnnotation.m :
#import "MyAnnotation.h"
#import "MyAppDelegate.h"
#implementation MyAnnotation
#synthesize title, subtitle;
#synthesize longitude;
#synthesize latitude;
-(id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil)
{
NSLog(#"add observer");
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(receivedNewUserLocation:) name:GMAP_USERLOCATION_CHANGED object:nil];
}
return self;
}
- (void)setTitleAndSubtitle
{
[self setTitleAndSubtitle:nil];
}
- (id)setTitleAndSubtitle:(CLLocation*)userLocation
{
CLLocationDistance dist = -1;
if(userLocation)
{
CLLocation *poiLoc = [[CLLocation alloc] initWithLatitude:self.latitude longitude:self.longitude];
dist = [userLocation distanceFromLocation:poiLoc] / 1000;
NSLog(#"distance is now %.f", dist);
}
title = #"the Title of the poi!";
subtitle = [NSString stringWithFormat:#"Distance: %#",
dist > -1 ? [NSString stringWithFormat:#"%.2f km", dist] : #"-"
];
return self;
}
- (void)receivedNewUserLocation:(NSNotification *)userLocationNotification
{
CLLocation *userlocation = (CLLocation*)[userLocationNotification object];
[self setTitleAndSubtitle:userlocation];
}
- (CLLocationCoordinate2D)coordinate;
{
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = latitude;
theCoordinate.longitude = longitude;
return theCoordinate;
}
- (NSString *)title
{
return title;
}
- (NSString *)subtitle
{
return subtitle;
}
- (void)dealloc
{
[title release];
[subtitle release];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self];
[super dealloc];
}
#end
In the end I use it like that in my MapViewController (I put only the viewForAnnotation delegate method here):
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation
{
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MyAnnotation *annotationView = nil;
MyAnnotation* myAnnotation = (MyAnnotation *)annotation;
// try to dequeue an existing pin view first
NSString* identifier = #"CustomMapAnnotation";
MyAnnotation *customPinView = (MyAnnotation *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(nil == customPinView)
{
// if an existing pin view was not available, create one
customPinView = [[[MyAnnotation alloc]
initWithAnnotation:myAnnotation
reuseIdentifier:identifier]
autorelease];
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
}
annotationView = customPinView;
[annotationView setEnabled:YES];
[annotationView setCanShowCallout:YES];
return annotationView;
}
After all of this subtitle is not update after the mkannotation is load on map....
What's wrong ?
thanks for your help...
When you update the title, you should notify the MKAnnotationView to update the callout view, by whichever KVO manner that fits your need best, e.g.:
synthesize or implement setter for title and use
self.title = #"new title";
use explicit KVO notifications
[self willChangeValueForKey:#"title"];
[title release];
title = [newTitle copy];
[self didChangeValueForKey:#"title"];
Ditto for subtitle.
It depends on how you are creating your MKAnnotations.
You should probably have an object like "Place" represented by Place.h and Place.m, which conform to the MKAnnotation protocol...
Place would have a property along the lines of
float distance;
Then your subtitle method (part of MKAnnotation) would do something like this
- (NSString *)subtitle
{
return [NSString stringWithFormat:#"%0.2f Miles Away", distance];
}
That subtitle method gets called by the mapview constantly (in fact its almost ridiculous how often it gets called), so as soon as you manipulate the value of distance, it will be reflected on the map (perhaps as early as the next time you tap on the pin).