how to get GPS Coordinates in iphone using Objective C - iphone

i want to get the GPS coordinates from iphone and send these GPS coordinates to web service. This web service, will take my GPS Coordinates and send me the location of the nearest ATM, from the current location.
now i want to do this in 2 phases.
First phase , i want to just send the GPS Coordinates to web service, and in return i want the address of the ATM location.
Second phase , i want to point this ATM on the MAP displayed in iphone app.
I have the web service developed, which take 2 input parameters : lat and longi.
and returns me the address of the ATM location in a string format.
To start with Phase 1 : Please help me with how to get the GPS cordinates and send it to the web service.
so that i can just display the address in string format(Result i get from web service) on the view.

Add Core Location to your project:
Highlight the application target.
Click on the Build Phases tab and expand the Link Binary with Libraries section.
Then click the + button and choose the CoreLocation framework.
Header File (.h)
Note the use of the delegate!
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#class DetailViewController;
#interface MasterViewController : UITableViewController<CLLocationManagerDelegate>
#property (nonatomic, retain) CLLocationManager *locationManager;
#end
Implementation File (.m)
#import "MasterViewController.h"
#implementation MasterViewController
#pragma mark - Properties
#synthesize locationManager;
#pragma mark - Methods
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
[self initializeMenuItems];
if (self.locationManager == nil)
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy =
kCLLocationAccuracyNearestTenMeters;
self.locationManager.delegate = self;
}
[self.locationManager startUpdatingLocation];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Turn off the location manager to save power.
[self.locationManager stopUpdatingLocation];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1. Get the current location
CLLocation *curPos = locationManager.location;
NSString *latitude = [[NSNumber numberWithDouble:curPos.coordinate.latitude] stringValue];
NSString *longitude = [[NSNumber numberWithDouble:curPos.coordinate.longitude] stringValue];
NSLog(#"Lat: %#", latitude);
NSLog(#"Long: %#", longitude);
}
- (void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"%#", #"Core location has a position.");
}
- (void) locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"%#", #"Core location can't get a fix.");
}
#end

Add CoreLocation framework to your project
Create and setup an instance of CLLocationManager (e.g. set desiredAccuracy property)
Set a delegate to your location manager
In your delegate implement 2 methods: -didFailWithError and -didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
Call -startUpdatingLocation on your location manager.
In didUpdate method you get all updates in your current location and can also check if the coordinates you get is valid for you (check horizontalAccuracy and timeStamp properties)

This sample code from apple (edit: link moved) : https://developer.apple.com/library/content/samplecode/LocateMe/
You have to ask user permission, adding this property in you plist : NSLocationWhenInUseUsageDescription
then, here is basically how apple does in a viewController (copied from link above) :
/*
Copyright (C) 2014 Apple Inc. All Rights Reserved.
See LICENSE.txt for this sample’s licensing information
*/
#import "GetLocationViewController.h"
#import "LocationDetailViewController.h"
#import "SetupViewController.h"
#import "CLLocation+Strings.h"
#interface GetLocationViewController () <SetupViewControllerDelegate, CLLocationManagerDelegate>
#property (nonatomic, weak) IBOutlet UIButton *startButton;
#property (nonatomic, weak) IBOutlet UILabel *descriptionLabel;
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#property (nonatomic, strong) SetupViewController* setupViewController;
#property (nonatomic, copy) NSString *stateString;
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) NSDateFormatter *dateFormatter;
#property (nonatomic, strong) NSMutableArray *locationMeasurements;
#property (nonatomic, strong) CLLocation *bestEffortAtLocation;
#end
#pragma mark -
#implementation GetLocationViewController
- (void)viewDidLoad {
[super viewDidLoad];
_locationMeasurements = [NSMutableArray array];
}
- (NSDateFormatter *)dateFormatter {
if (_dateFormatter == nil) {
_dateFormatter = [[NSDateFormatter alloc] init];
[_dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[_dateFormatter setTimeStyle:NSDateFormatterLongStyle];
}
return _dateFormatter;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UINavigationController *nv = segue.destinationViewController;
_setupViewController = nv.viewControllers[0];
self.setupViewController.delegate = self;
}
#pragma mark - Actions
// The reset method allows the user to repeatedly test the location functionality.
// In addition to discarding all of the location measurements from the previous "run",
// it animates a transition in the user interface between the table which displays location
// data and the start button and description label presented at launch.
//
- (void)reset {
_bestEffortAtLocation = nil;
[self.locationMeasurements removeAllObjects];
// fade in the rest of the UI and fade out the table view
[UIView animateWithDuration:0.6f animations:^(void) {
self.startButton.alpha = 1.0;
self.descriptionLabel.alpha = 1.0;
self.tableView.alpha = 0.0;
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
} completion:^(BOOL finished) {
if (finished) {
//..
}
}];
}
#pragma mark - Location Manager Interactions
// This method is invoked when the user hits "Done" in the setup view controller.
// The options chosen by the user are passed in as a dictionary. The keys for this dictionary
// are declared in SetupViewController.h.
//
- (void)setupViewController:(SetupViewController *)controller didFinishSetupWithInfo:(NSDictionary *)setupInfo {
self.startButton.alpha = 0.0;
self.descriptionLabel.alpha = 0.0;
self.tableView.alpha = 1.0;
// Create the core location manager object
_locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// This is the most important property to set for the manager. It ultimately determines how the manager will
// attempt to acquire location and thus, the amount of power that will be consumed.
self.locationManager.desiredAccuracy = [setupInfo[kSetupInfoKeyAccuracy] doubleValue];
// Once configured, the location manager must be "started"
//
// for iOS 8, specific user level permission is required,
// "when-in-use" authorization grants access to the user's location
//
// important: be sure to include NSLocationWhenInUseUsageDescription along with its
// explanation string in your Info.plist or startUpdatingLocation will not work.
//
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
[self performSelector:#selector(stopUpdatingLocationWithMessage:)
withObject:#"Timed Out"
afterDelay:[setupInfo[kSetupInfoKeyTimeout] doubleValue]];
self.stateString = NSLocalizedString(#"Updating", #"Updating");
[self.tableView reloadData];
}
// We want to get and store a location measurement that meets the desired accuracy.
// For this example, we are going to use horizontal accuracy as the deciding factor.
// In other cases, you may wish to use vertical accuracy, or both together.
//
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// store all of the measurements, just so we can see what kind of data we might receive
[self.locationMeasurements addObject:newLocation];
// test the age of the location measurement to determine if the measurement is cached
// in most cases you will not want to rely on cached measurements
//
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) {
return;
}
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) {
return;
}
// test the measurement to see if it is more accurate than the previous measurement
if (self.bestEffortAtLocation == nil || self.bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy) {
// store the location as the "best effort"
_bestEffortAtLocation = newLocation;
// test the measurement to see if it meets the desired accuracy
//
// IMPORTANT!!! kCLLocationAccuracyBest should not be used for comparison with location coordinate or altitidue
// accuracy because it is a negative value. Instead, compare against some predetermined "real" measure of
// acceptable accuracy, or depend on the timeout to stop updating. This sample depends on the timeout.
//
if (newLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy) {
// we have a measurement that meets our requirements, so we can stop updating the location
//
// IMPORTANT!!! Minimize power usage by stopping the location manager as soon as possible.
//
[self stopUpdatingLocationWithMessage:NSLocalizedString(#"Acquired Location", #"Acquired Location")];
// we can also cancel our previous performSelector:withObject:afterDelay: - it's no longer necessary
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(stopUpdatingLocationWithMessage:) object:nil];
}
}
// update the display with the new location data
[self.tableView reloadData];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
// The location "unknown" error simply means the manager is currently unable to get the location.
// We can ignore this error for the scenario of getting a single location fix, because we already have a
// timeout that will stop the location manager to save power.
//
if ([error code] != kCLErrorLocationUnknown) {
[self stopUpdatingLocationWithMessage:NSLocalizedString(#"Error", #"Error")];
}
}
- (void)stopUpdatingLocationWithMessage:(NSString *)state {
self.stateString = state;
[self.tableView reloadData];
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
UIBarButtonItem *resetItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Reset", #"Reset")
style:UIBarButtonItemStylePlain
target:self
action:#selector(reset)];
[self.navigationItem setLeftBarButtonItem:resetItem animated:YES];
}
#pragma mark - UITableViewDataSource
// The table view has three sections. The first has 1 row which displays status information.
// The second has 1 row which displays the most accurate valid location measurement received.
// The third has a row for each valid location object received
// (including the one displayed in the second section) from the location manager.
//
- (NSInteger)numberOfSectionsInTableView:(UITableView *)table {
return (self.bestEffortAtLocation != nil) ? 3 : 1;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *headerTitle = nil;
switch (section) {
case 0: {
headerTitle = NSLocalizedString(#"Status", #"Status");
break;
}
case 1: {
headerTitle = NSLocalizedString(#"Best Measurement", #"Best Measurement");
break;
}
default: {
headerTitle = NSLocalizedString(#"All Measurements", #"All Measurements");
break;
}
}
return headerTitle;
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
NSInteger numRows = 0;
switch (section) {
case 0: {
numRows = 1;
break;
}
case 1: {
numRows = 1;
break;
}
default: {
numRows = self.locationMeasurements.count;
break;
}
}
return numRows;
}
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
switch (indexPath.section) {
case 0: {
// The cell for the status row uses the cell style "UITableViewCellStyleValue1", which has a label on the left side of the cell with left-aligned and black text; on the right side is a label that has smaller blue text and is right-aligned. An activity indicator has been added to the cell and is animated while the location manager is updating. The cell's text label displays the current state of the manager.
static NSString * const kStatusCellID = #"StatusCellID";
static NSInteger const kStatusCellActivityIndicatorTag = 2;
UIActivityIndicatorView *activityIndicator = nil;
cell = [table dequeueReusableCellWithIdentifier:kStatusCellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kStatusCellID];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGRect frame = activityIndicator.frame;
frame.origin = CGPointMake(290.0, 12.0);
activityIndicator.frame = frame;
activityIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
activityIndicator.tag = kStatusCellActivityIndicatorTag;
[cell.contentView addSubview:activityIndicator];
} else {
activityIndicator = (UIActivityIndicatorView *)[cell.contentView viewWithTag:kStatusCellActivityIndicatorTag];
}
cell.textLabel.text = self.stateString;
if ([self.stateString isEqualToString:NSLocalizedString(#"Updating", #"Updating")]) {
if (activityIndicator.isAnimating == NO) {
[activityIndicator startAnimating];
}
} else {
if (activityIndicator.isAnimating) {
[activityIndicator stopAnimating];
}
}
break;
}
case 1: {
// The cells for the location rows use the cell style "UITableViewCellStyleSubtitle", which has a left-aligned label across the top and a left-aligned label below it in smaller gray text. The text label shows the coordinates for the location and the detail text label shows its timestamp.
static NSString * const kBestMeasurementCellID = #"BestMeasurementCellID";
cell = [table dequeueReusableCellWithIdentifier:kBestMeasurementCellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kBestMeasurementCellID];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = self.bestEffortAtLocation.localizedCoordinateString;
cell.detailTextLabel.text = [self.dateFormatter stringFromDate:self.bestEffortAtLocation.timestamp];
break;
}
default: {
// The cells for the location rows use the cell style "UITableViewCellStyleSubtitle", which has a left-aligned label across the top and a left-aligned label below it in smaller gray text. The text label shows the coordinates for the location and the detail text label shows its timestamp.
static NSString * const kOtherMeasurementsCellID = #"OtherMeasurementsCellID";
cell = [table dequeueReusableCellWithIdentifier:kOtherMeasurementsCellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kOtherMeasurementsCellID];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
CLLocation *location = self.locationMeasurements[indexPath.row];
cell.textLabel.text = location.localizedCoordinateString;
cell.detailTextLabel.text = [self.dateFormatter stringFromDate:location.timestamp];
break;
}
}
return cell;
}
#pragma mark - UITableViewDelegate
// Delegate method invoked before the user selects a row.
// In this sample, we use it to prevent selection in the first section of the table view.
//
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
return (indexPath.section == 0) ? nil : indexPath;
}
// Delegate method invoked after the user selects a row. Selecting a row containing a location object
// will navigate to a new view controller displaying details about that location.
//
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
CLLocation *location = self.locationMeasurements[indexPath.row];
LocationDetailViewController *detailVC = [[LocationDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
detailVC.location = location;
[self.navigationController pushViewController:detailVC animated:YES];
}
#end

Import CoreLocation framework to app
import CoreLocation/CoreLocation.h librarie to ViewController
edit ViewController header file
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface EMViewController : UIViewController <CLLocationManagerDelegate>{
CLLocationManager *locationManager;
}
#end
initialize locationManager in ViewController implementation
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];
NSLog(#" lat: %f",locationManager.location.coordinate.latitude);
NSLog(#" lon: %f",locationManager.location.coordinate.longitude);
[locationManager stopUpdatingLocation];
}

Related

How to make SearchBar in tableview work?

So i am trying to make an application that displays names of people in a tableview and on tap moves to the next view controller that shows an image of the person.
However when i add the search bar on the table view; i dont seem to have it right.
What am i doing wrong here?
The code compiles and displays on the simulator but when i click on any of the buttons, it gives me the errors i hate the most (Thread 1 : signal SIGABRT)
Here is my code for the Table View Controller
#import "PhotoTableViewController.h"
#import "Photo.h"
#import "DisplayViewController.h"
#interface PhotoTableViewController ()
#end
#implementation PhotoTableViewController
#synthesize photoSearchBar, showPhotos, filteredPhotos;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
showPhotos = [NSArray arrayWithObjects:
[Photo photoofname:#"Main" filename:#"photo1.jpg" notes:#"Amazing Road Bike"],
[Photo photoofname:#"Back" filename:#"photo3.jpg" notes:#"this is the back"], nil];
[self.tableView reloadData];
self.filteredPhotos = [NSMutableArray arrayWithCapacity:[showPhotos count]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [filteredPhotos count];
} else {
return [showPhotos count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Photo *photo = nil;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
photo = [filteredPhotos objectAtIndex:indexPath.row];
}else
{
photo = [showPhotos objectAtIndex:indexPath.row];
}
cell.textLabel.text = photo.name;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
#pragma mark Content Filtering
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredPhotos removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name contains[c] %#",searchText];
filteredPhotos = [NSMutableArray arrayWithArray:[showPhotos filteredArrayUsingPredicate:predicate]];
}
#pragma mark - UISearchDisplayController Delegate Methods
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// Tells the table data source to reload when text changes
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
// Tells the table data source to reload when scope bar selection changes
[self filterContentForSearchText:self.searchDisplayController.searchBar.text scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#pragma mark - TableView Delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Perform segue to candy detail
[self performSegueWithIdentifier:#"candyDetail" sender:tableView];
}
#pragma mark - Segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"photoDetail"]) {
UIViewController *candyDetailViewController = [segue destinationViewController];
// In order to manipulate the destination view controller, another check on which table (search or normal) is displayed is needed
if(sender == self.searchDisplayController.searchResultsTableView) {
NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
NSString *destinationTitle = [[filteredPhotos objectAtIndex:[indexPath row]] name];
[candyDetailViewController setTitle:destinationTitle];
}
else {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *destinationTitle = [[showPhotos objectAtIndex:[indexPath row]] name];
[candyDetailViewController setTitle:destinationTitle];
}
}
}
Also this is the code for my Objective C Class called Photo
#import "Photo.h"
#implementation Photo
#synthesize name,filename,notes;
+(id) photoofname: (NSString*)name filename:(NSString*)filename notes:(NSString*)notes{
Photo *newPhoto = [[Photo alloc]init];
newPhoto.name = name;
newPhoto.filename = filename;
newPhoto.notes = notes;
return newPhoto;
}
#end
Well, just by looking at the code what I can suggest you is, first remove that call to prepareForSegue method called in UITableView's delegate method, didSelectForRowAtIndexPath.
You are overriding prepareForSegue, so in your storyboard you should have a prototype cell from where you have to ctrl-drag to the destination controller and segue it accordingly. That's a basic concept. Still having problem? Let us see your console messages when it crashes.

Obj-C globally use NSArray

I have a ViewController that prompts the FBFriendPickerViewController in which I, at selection, am returned with an NSArray containing the selection. Now I want to prompt and show a new ViewController using this selection information. I am new to Objective C, but I guess the solution is pretty simple. Here is my proposal:
ViewController2.h
- (id)initWithStyle:(UITableViewStyle)style andSelection:(NSArray *)selection;
#property (strong, nonatomic) NSArray *selectedParticipants;
ViewController2.m
- (id)initWithStyle:(UITableViewStyle)style andSelection:(NSArray *)selection {
self = [super initWithStyle:style];
if (self) {
self.title = NSLocalizedString(#"Split Bill", nil);
self.tableView.backgroundColor = [UIColor wuffBackgroundColor];
self.selectedParticipants = selection;
}
return self;
}
- (void)setSelectedParticipants:(NSArray *)selectedParticipants {
NSLog(#"setSelectedParticipants (%d)", [selectedParticipants count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"%d rowsInSection", [self.selectedParticipants count]);
return [self.selectedParticipants count];
}
ViewController1.m
- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex {
if (buttonIndex == 2) {
[[self friendPickerController] presentModallyFromViewController:self animated:YES handler:^(FBViewController *sender, BOOL donePressed) {
if (donePressed) {
ViewController2 *vc = [[ViewController2 alloc] initWithStyle:UITableViewStyleGrouped
andSelection:[self.friendPickerController selection]];
[self.navigationController pushViewController:vc animated:YES];
}
//[[self friendPickerController] clearSelection];
}
];
}
}
It seems, however, that the first setSelectedParticipants-log returns the correct amount of selected friends, but the numberOfRowsInSection-log returns 0.
Why is this?
Thanks in advance!
The problem here is in your setter:
- (void)setSelectedParticipants:(NSArray *)selectedParticipants {
NSLog(#"setSelectedParticipants (%d)", [selectedParticipants count]);
}
You will notice that you never actually set the value for the instance variable backing the property, in this case, the default is _selectedParticipants. So, to fix, simply add the following line to your setter:
_selectedParticipants = selectedParticipants;
And you should be good to go.
Remove this function from your code
- (void)setSelectedParticipants:(NSArray *)selectedParticipants {
NSLog(#"setSelectedParticipants (%d)", [selectedParticipants count]);
}
You are already set the selectedParticipants in init method

Pass data from a table to a webview USING SEGUES

I have a table based off Sam's Teach Yourself iOS Development's FlowerViewController, that, under didSelectRowAtIndesPath it goes to a website in a new nib (I tweaked part of the passing data).
MY QUESTION: I would like to update this to, instead of going to a nib, to segue within a storyboard. I know that instead of using didSelectRow... I use prepareForSegue...but I can't figure out the details...
my I have ViewController.m with the following:
- (void)viewDidLoad {
[self movieData];
[super viewDidLoad];
self.title = #"Movies";
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [movieSections count];
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[movieData objectAtIndex:section] count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier];
}
// Configure the cell.
[[cell textLabel]
setText:[[[movieData
objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]
objectForKey:#"name"]];
[[cell imageView]
setImage:[UIImage imageNamed:[[[movieData
objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]
objectForKey:#"picture"]]];
[[cell detailTextLabel]
setText:[[[movieData
objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]
objectForKey:#"detail"]];
cell.detailTextLabel.numberOfLines = 0;
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
// Override to support row selection in the table view.
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
WebViewController *webViewController =
[[WebViewController alloc] initWithNibName:
#"WebViewController" bundle:nil];
webViewController.detailURL=
[[NSURL alloc] initWithString:
[[[movieData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:#"url"]];
webViewController.title=
[[[movieData objectAtIndex:indexPath.section] objectAtIndex:
indexPath.row] objectForKey:#"name"];
[self.navigationController pushViewController:
webViewController animated:YES];
}
#pragma mark -
#pragma mark Table view delegate
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)movieData {
NSMutableArray *myMovies;
movieSections=[[NSMutableArray alloc] initWithObjects:
#"Movies",nil];
myMovies=[[NSMutableArray alloc] init];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"Movie1",#"name",
#"1.png",#"picture",
#"http://www.url1.com",#"url",#"Some information",#"detail",nil]];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"Movie2",#"name",
#"2.png",#"picture",
#"http://www.url2.com",#"url",#"Some information 2",#"detail",nil]];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"Movie3",#"name",
#"3.png",#"picture",
#"http://www.url3.com",#"url",#"Some information 3",#"detail",nil]];
[myMovies addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"Movie4",#"name",
#"4.png",#"picture",
#"http://www.url4.com",#"url",#"Some information 4",#"detail",nil]];
movieData=[[NSMutableArray alloc] initWithObjects:
myMovies,nil];
}
I attempted to comment out the didSelectRowAtIndexPath and add the following for the segue, but the cell highlights and nothing happens (thankfully it doesn't freeze/crash, but there's nothing positive)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"movieSegue"]) {
NSIndexPath *selectedRowIndex = [self.tableView indexPathForSelectedRow];
WebViewSegue *_webViewSegue = [segue destinationViewController];
_webViewSegue.detailURL =
[[NSURL alloc] initWithString:[[[movieData objectAtIndex:selectedRowIndex.section] objectAtIndex:
selectedRowIndex.row] objectForKey:#"url"]];
}
}
Then I want it to pass to WebViewSegue
WebViewSegue.h:
#interface WebViewSegue : UIViewController {
IBOutlet UIWebView *detailWebView;
NSURL *detailURL;
IBOutlet UIActivityIndicatorView *activity;
NSTimer *timer;
}
#property (nonatomic, weak) NSURL *detailURL;
#property (nonatomic, weak) UIWebView *detailWebView;
#property (nonatomic, weak) UIActivityIndicatorView *activity;
#end
WebViewSegue.m:
#synthesize detailWebView =_detailWebView;
#synthesize detailURL = _detailURL;
#synthesize activity =_activity;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
[detailWebView loadRequest:[NSURLRequest requestWithURL:detailURL]];
timer = [NSTimer scheduledTimerWithTimeInterval:(1.0/2.0)
target:self
selector:#selector(tick)
userInfo:nil
repeats:YES];
}
-(void)tick {
if (!detailWebView.loading)
[activity stopAnimating];
else
[activity startAnimating];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(void)wevView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Cannot connect"
message:#"Please check your connection and try again"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
#end
I've answered your question in another post on the site. See my answer here.
Specifically on how to pass data from a table to the next storyboard segue, first create a property for the data in the next storyboard segue (i.e. the destination view controller). Then set that property in the prepareForSegue method of the table (the source view controller).
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// needed if you have multiple segues
if ([[segue identifier] isEqualToString:#"changeNameAndDate"])
{
[[segue destinationViewController] setDataProperty:self.tableData];
// where dataProperty is the property in the designation view controller
// and tableData is the data your are passing from the source
{
}
This is a lot of code to digest; you should try to simplify. But if I've read it correctly, your basic approach seems correct.
First, put a breakpoint on prepareForSegue:sender:, and make sure it's being called, and that the identifier is what you expect it to be.
Then put a breakpoint on viewDidLoad and make sure it's called when you think it should be.
I would pull the loadRequest: out into its own method and call it both in viewDidLoad and in setDetailURL:. It's likely that setDetailURL: is being called after viewDidLoad if all of this is in a single storyboard.
EDIT What I'm saying is that prepareForSegue:sender: is likely correct. You're problem is in the presented view controller.
- (void)reloadWebView { // Pull the loadRequest: out...
[self.detailWebView loadRequest:[NSURLRequest requestWithURL:self.detailURL]];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self reloadWebView]; // ...and call it both in viewDidLoad...
...
}
- (void)setDetailURL:(NSURL *)URL {
[URL retain];
[detailURL release];
detailURL = URL;
[self reloadWebView]; // ...and in setDetailURL:
}
Also note that there is no reason for your timer. Just turn on your progress indicator in reloadWebView and turn it off in webViewDidFinishLoad and webView:didFailLoadWithError:. Your current approach makes it impossible to deallocate this view controller because the timer retains it forever.

Updating location iPhone App

I'm trying to get the app to update the user's location as the user moves, and update POI based on his location. It doesn't work right now (the user's location stays the same even if he moves by a lot). Can anybody help me out?
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
locationManager.distanceFilter = 1000;
[mapView removeAnnotations: mapView.annotations];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
homeCoordinate = newLocation.coordinate;
if (!home1Annotation) {
home1Annotation = [[MyMapAnnotation alloc] initWithCoordinate:homeCoordinate
title:#"Current Location"
];
[mapView addAnnotation:home1Annotation];
[self adjustMapZoom];
[self loadAndSortPOIs];
for (int j =0 ; j <5 ; j++){
[self displayPOIs];
}
}
}
My Map Annotation
#import "MyMapAnnotation.h"
#implementation MyMapAnnotation
#synthesize coordinate;
#pragma mark initializers
// designated initializer
-(id) initWithCoordinate:(CLLocationCoordinate2D)coordinateQ title:(NSString*) titleQ {
if ( self = [super init]) {
coordinate = coordinateQ;
title = titleQ;
[title retain];
}
return self;
}
-(void) dealloc {
[title release];
[super dealloc];
}
#pragma mark MKAnnotation implementation
-(NSString*) title { return title; }
-(NSString*) subtitle { return nil; }
#end
Two things go wrong:
1) ask for the highest accuracy: kCLLocationAccuracyBest instead of kCLLocationAccuracyHundredMeters. Don't set distanceFilter or set it to zero.
2) in didUpdateToLocation, add a line
NSLog(#"Location update: %#",newLocation);
and watch logfile output. Your if statement makes that the code block below is only run once. I would expect an else block, which will update the POI location in case the home1Annotation already exists. Something like:
} else {
[MyMapAnnotation setCoordinate:homeCoordinate];
}
(but I do not know your class MyMapAnnotation so this is guessing)
There shouldn't be any problems, all will work, but in your case next call about user location changed will be called when user will cane their place from recent detection on distance of 1 kilometer as you specified by this code locationManager.distanceFilter = 1000;

dimissModalViewControllerAnimated causing tableView to be full screen?

I have a RootViewController with 2 tableViews as subviews (created in IB) each with their own tableViewController class (handleing fetchRequests etc.)
1 tableView is static (no data changed by user or modelViews).
tableView 2 has a button in the header which presents an imagePickerController.
No issues so far.
Problem is, when i dismiss the imagePicker
[self dismissModalViewControllerAnimated:YES];
TableView 2 becomes full screen i have tried
[[self rootViewController] dismissModalViewControllerAnimated:YES]
Nothing happens at all. It sticks on the image picker.
I suspect this is due to there being very little of the view being created programmaticaly.
Any ideas?
Thanks in advance.
DetartrateD
-(IBAction)addImageTableAPressed {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
}
RootViewController
|| ||
|| ||
\/ \/ addImageTableAPressed
TableViewControlA TableViewControlB --------------------->modelViewController
To resolve mananagedObjectContect.....
- (void)viewDidLoad {...
if(managedObjectContext == nil)
{
managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSLog(#"After managedObjectContext: %#", managedObjectContext);
}
...
}
As I mentioned in one of my comments, I would prefer having a single view controller managing the two table views. Define a UIView (the rootView) including 2 subviews (tableViewA and tableViewB). Your RootViewController's view will be rootView, and this controller will have to be the data source and delegate of both table views. The code I will give here is by no means complete nor optimal, but gives you a good idea of what is needed to implement my solution.
For example:
#interface RootViewController <UITableViewDelegate, UITableViewDataSource> {
NSArray *dataArrayA;
NSArray *dataArrayB;
UITableView tableViewA;
UITableView tableViewB;
NSManagedObjectContext *context;
}
#property (nonatomic, retain) NSArray *dataArrayA;
#property (nonatomic, retain) NSArray *dataArrayB;
// in IB, link the dataSource and delegate outlets of both tables to RootViewController
#property (nonatomic, retain) IBOutlet UITableView tableViewA;
#property (nonatomic, retain) IBOutlet UITableView tableViewB;
// this property will allow you to pass the MOC to the RootViewController from
// the parent view controller, instead of accessing the app delegate from RootViewController
#property (nonatomic, retain) NSManagedObjectContext *context;
// ... etc.
#end
#implementation RootViewController
#synthesize dataArrayA;
#synthesize dataArrayB;
#synthesize tableViewA;
#synthesize tableViewB;
#synthesize context;
// initialize dataArrayA and dataArrayB
- (void)viewDidLoad {
[super viewDidLoad];
NSError *error = nil;
// initialize and configure your fetch request for data going into tableViewA
NSFetchRequest fetchRequestA = [[NSFetchRequest alloc] init];
// configure the entity, sort descriptors, predicate, etc.
// ...
// perform the fetch
self.dataArrayA = [context executeFetchRequest:fetchRequestA error:&error];
// do the same for the data going into tableViewB - the code is very similar, you
// could factor it out in a private method instead of duplicating it here
// NSFetchRequest fetchRequestB = [[NSFetchRequest alloc] init];
// omitting the details ... etc.
self.dataArrayB = [context executeFetchRequest:fetchRequestB error:&error];
// release objects you don't need anymore, according to memory management rules
[fetchRequestA release];
[fetchRequestB release];
}
// Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// if you have a different number of sections in tableViewA and tableViewB
/*
if (tableView == tableViewA) {
return ??;
} else {
return ??
}
*/
// otherwise, if both table views contain one section
return 1;
}
// Customize the number of rows in each table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == tableViewA) {
return [dataArrayA count];
} else {
return [dataArrayB count];
}
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
if (tableView == tableViewA) {
// get the data for the current row in tableViewA
id objectA = [dataArrayA objectAtIndex:indexPath.row];
// configure the cell for tableViewA
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierA];
// etc...
} else {
// get the data for the current row in tableViewB
id objectB = [dataArrayB objectAtIndex:indexPath.row];
// configure the cell for tableViewB
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierB];
// etc...
}
return cell;
}
// And so on, the same idea applies for the other UITableViewDelegate you would need to
// implement...
- (void)dealloc {
[dataArrayA release];
[dataArrayB release];
[tableViewA release];
[tableViewB release];
[context release];
// etc...
[super dealloc];
}
#end
I hope you'll find this useful.