I have a two view controllers (DatePickerViewController and RouteHistoryViewController). I also have the server response in DatePickerViewController. How can I pass that response to the RouteHitoryViewController. The RouteHistoryViewController has a map view.
Here is the code DatePicker.m :
#import "DatePickerViewController.h"
#import "MapAnnotation.h"
#interface DatePickerViewController ()
#end
#implementation DatePickerViewController
{
//#define URL #"http://140e3087.ngrok.com"
#define URL3 #"http://784effb4.ngrok.com/bustracking/json/student/route_history"
NSString *formatedDate;
NSString *lat;
NSString *longi;
NSString *server_created_date;
}
#synthesize appDelagate,datePicker;
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"%#", appDelegate);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm"];
formatedDate = [dateFormatter stringFromDate:self.datePicker.date];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)sendPicker:(id)sender;
{
[self sendDataToServer : #"GET"];
// NSLog(#"%#", formatedDate);
//self.selectedDate.text =formatedDate;
}
-(void) sendDataToServer : (NSString *) method{
NSString *beaconiD = #"EC112729B51B";
NSString *trackerID = #"e61078a67e4233ad";//appDelagate.tracker_id;
NSString *date = formatedDate;
NSMutableURLRequest *request = nil;
NSString *getURL = [NSString stringWithFormat:#"%#?beacon_id=%#&tracker_id=%#&date=%#", URL3, beaconiD, trackerID, date];
getURL = [getURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString: getURL];
request = [NSMutableURLRequest requestWithURL:url];
NSLog(#"link: %#", getURL);
[request setHTTPMethod:#"GET"];
[request addValue: #"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"connection: %#", connection);
if( connection )
{
mutData = [NSMutableData new];
}
else
{
NSLog (#"NO_CONNECTION");
return;
}
}
#pragma mark NSURLConnection delegates
-(void) connection:(NSURLConnection *) connection didReceiveResponse:(NSURLResponse *)response
{
[mutData setLength:0];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[mutData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog (#"NO_CONNECTION");
return;
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// NSString *jsonresultString =[jsonresultDict objectForKey:#"result"];
// NSLog(#"%#", jsonresultString);
// //serverResponse.text = jsonresultString;
NSError *error = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:mutData options:kNilOptions error:&error];
NSArray *fetchedArr = [json objectForKey:#"result"];
for (NSDictionary *user in fetchedArr)
{
lat = [user objectForKey:#"latitude"];
longi = [user objectForKey:#"longitude"];
server_created_date = [user objectForKey:#"server_created_date"];
NSLog(#"Item date&time : %#", server_created_date);
NSLog(#"Item longitude : %#", longi);
NSLog(#"Item latitude : %#", lat);
}
}
Here is the code RouteHistory.m:
#import "RouteHistoryViewController.h"
#import "MapAnnotation.h"
#interface RouteHistoryViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
#implementation RouteHistoryViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView.delegate = self;
//[self.mapView removeAnnotations:self.mapView.annotations];
MapAnnotation *mapPoint = [[MapAnnotation alloc] init];
mapPoint.coordinate = CLLocationCoordinate2DMake([self.appDelagate.latitude doubleValue], [self.appDelagate.longitude doubleValue]);
mapPoint.title = self.appDelagate.name;
mapPoint.time = self.appDelagate.server_created_date;
mapPoint.mapimage = self.appDelagate.image;
// Add it to the map view
[self.mapView addAnnotation:mapPoint];
// Zoom to a region around the pin
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(mapPoint.coordinate, 500, 500);
[self.mapView setRegion:region];
//testing
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"MapUpdate"
object:nil];
// Do any additional setup after loading the view.
}
#pragma mark - MKMapViewDelegate
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
MKPinAnnotationView *view = nil;
static NSString *reuseIdentifier = #"MapAnnotation";
// Return a MKPinAnnotationView with a simple accessory button
view = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseIdentifier];
if(!view)
{
view = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
view.canShowCallout = YES;
view.animatesDrop = YES;
}
return view;
}
datepicker to route history using prepareforsegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier]isEqualToString:#"b"])
{
RouteHistoryViewController *rh = segue.destinationViewController;
NSLog(#"%#", rh);
}
}
In first view controller inside connectionDidFinishLoading after this line
NSArray *fetchedArr = [json objectForKey:#"result"];
add the following two lines
_responseFromServer = fetchedArr;
[self performSegueWithIdentifier:#"segueToRouteHistory" sender:self];
and then add this method in your first View Controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"segueToRouteHistory"])
{
RouteHistoryViewController *routeHistoryController = [segue segueToRouteHistory];
[routeHistoryController setFetchedArray:_responseFromServer];
}
}
In your First View Controller .h file add this
#property NSArray *responseFromServer;
Now We have assigned the Response array received from server to a object in your destination view controller.
Don't forget to add
#property NSArray *fetchedArray;
inside your Second ViewController's .h file
Now you can access this array in second view controller.
PS: Do not forget to give segue from storyboard from first view controller to second view controller and name the Segue Identifier as "segueToRouteHistory"
Related
In my app I've a view controller in which there are a table view, when I tap on one of table view row it should dismiss the actual view controller an pass back an url to load it in a web view. I thought the right way to do that it's to implement a delegate, so I did it but when I try to run the app when I tap on the row of table view it doesn't call the delegate method.
I add here some code to understand what's wrong:
HistoryNotificationViewController.h
#import <UIKit/UIKit.h>
#protocol HistoryNotificationDelegate;
#interface HistoryNotificationViewController : UIViewController
#property(nonatomic,weak) id <HistoryNotificationDelegate> delegate;
#end
#protocol HistoryNotificationDelegate <NSObject>
- (void) updateWebViewWithURL:(NSString*)url;
#end
HistoryNotificationViewController.m (I post only the method in which I call the delegate method)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.delegate updateWebViewWithURL:[sortedArray[indexPath.row] objectForKey:#"url"]];
[self dismissViewControllerAnimated:YES completion:nil];
}
HomeViewController.m (view controller that should implement the delegate method of HistoryNotificationViewController.m)
#import "HomeViewController.h"
#import "SSKeychain.h"
#import "SSKeychainQuery.h"
#import "MBProgressHUD.h"
#import "HistoryNotificationViewController.h"
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
#interface HomeViewController () <UIWebViewDelegate, HistoryNotificationDelegate>
#property (weak, nonatomic) IBOutlet UIWebView *webView;
- (IBAction)buttonForward:(UIButton *)sender;
- (IBAction)buttonBack:(UIButton *)sender;
#property(nonatomic,strong)MBProgressHUD *hud;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.hud = [[MBProgressHUD alloc]init];
self.hud.labelText = #"Loading";
self.hud.mode = MBProgressHUDModeIndeterminate;
[self.view addSubview:self.hud];
NSURL *url = [[NSURL alloc]init];
NSURLRequest *request = [[NSURLRequest alloc]init];
if (!self.website) {
url = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:#"website" ]];
request = [NSURLRequest requestWithURL:url];
} else {
[[NSUserDefaults standardUserDefaults] setObject:self.website forKey:#"website"];
[[NSUserDefaults standardUserDefaults] synchronize];
url = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:#"website"]];
request = [NSURLRequest requestWithURL:url];
}
[self.webView loadRequest:request];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
HistoryNotificationViewController *historyNotificationViewController = [[HistoryNotificationViewController alloc]init];
[historyNotificationViewController setDelegate:self];
}
#pragma mark HistoryNotificationDelegate
- (void)updateWebViewWithURL:(NSString *)url {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[self.webView loadRequest:request];
}
#pragma mark UIWebViewDelegate
- (void)webViewDidStartLoad:(UIWebView *)webView {
[self.hud show:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self.hud hide:YES];
}
- (IBAction)buttonForward:(UIButton *)sender {
[self.webView goForward];
}
- (IBAction)buttonBack:(UIButton *)sender {
[self.webView goBack];
}
#end
What's wrong in my classes? Why it doesn't execute the delegate method?
Try this,
Make a property for HistoryNotificationViewController by
#property (nonatomic, strong) HistoryNotificationViewController *historyNotificationViewController;
and in prepareForSegue :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
UIViewController *destinationVC = [segue destinationViewController];
if ([destinationVC isKindOfClass:[HistoryNotificationViewController class]]) {
self.historyNotificationViewController = destinationVC;
[self.historyNotificationViewController setDelegate:self];
}
}
You need to get HistoryNotificationViewControllers in prepareForSegue from destinationViewController instead of allocating a new object...
#import "HomeViewController.h"
#import "SSKeychain.h"
#import "SSKeychainQuery.h"
#import "MBProgressHUD.h"
#import "HistoryNotificationViewController.h"
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
#interface HomeViewController () <UIWebViewDelegate, HistoryNotificationDelegate>{
}
#property (weak, nonatomic) IBOutlet UIWebView *webView;
- (IBAction)buttonForward:(UIButton *)sender;
- (IBAction)buttonBack:(UIButton *)sender;
#property(nonatomic,strong)MBProgressHUD *hud;
#end
#implementation HomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.hud = [[MBProgressHUD alloc]init];
self.hud.labelText = #"Loading";
self.hud.mode = MBProgressHUDModeIndeterminate;
[self.view addSubview:self.hud];
NSURL *url = [[NSURL alloc]init];
NSURLRequest *request = [[NSURLRequest alloc]init];
if (!self.website) {
url = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:#"website" ]];
request = [NSURLRequest requestWithURL:url];
} else {
[[NSUserDefaults standardUserDefaults] setObject:self.website forKey:#"website"];
[[NSUserDefaults standardUserDefaults] synchronize];
url = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:#"website"]];
request = [NSURLRequest requestWithURL:url];
}
[self.webView loadRequest:request];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE_FOR_HISTORY_NOTIFICATION_VIEWCONTROLLER"])
{
// Get reference to the destination view controller
HistoryNotificationViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setDelegate:self];
}
}
#pragma mark HistoryNotificationDelegate
- (void)updateWebViewWithURL:(NSString *)url {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[self.webView loadRequest:request];
}
#pragma mark UIWebViewDelegate
- (void)webViewDidStartLoad:(UIWebView *)webView {
[self.hud show:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self.hud hide:YES];
}
- (IBAction)buttonForward:(UIButton *)sender {
[self.webView goForward];
}
- (IBAction)buttonBack:(UIButton *)sender {
[self.webView goBack];
}
You do not need and should not use delegate at all in this case. Otherwise you're making thing complicated.
Just define a public method in your HomeViewController,
- (void)updateWebViewWithURL:(NSString *)url
{
}
Same method name as the one you've defined should be ok, but not as a delegate method!
Then, in your HistoryNotificationViewController.m, you'll be able to get a reference of HomeViewController easily. Something like this will do,
NSArray *viewControllers = self.navigationController.viewControllers;
HomeViewController *homeViewController = [viewControllers objectAtIndex:0];
[homeViewController updateWebViewWithURL:url];
my problem is rather simple but I can not seem to figure it out.
I am trying to add a refresh button to my mapview that will go back to the server and retrieve new locations if there have been any updates. My code below can already make the first call to the server with viewdidload method and can plot all the locations on the server to the map. What I need now is for a button that will make this same call whenever pressed, I am using one class for all my code so please your simplest solution that will easily merge with the code will be very much appreciated.
I am also very new to ios programming so any advice on how to tidy up my code will be also appreciated.
This is my view controller that contains all my code.
//ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView.delegate = self;
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
[self.mapView setShowsUserLocation:YES];
} else {
[locationManager requestWhenInUseAuthorization];
}
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://sample.name/service.php"];
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
#pragma mark NSURLConnectionDataProtocol Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_downloadedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_downloadedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSMutableArray *_locations = [[NSMutableArray alloc] init];
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_downloadedData options:NSJSONReadingAllowFragments error:&error];
CLLocationCoordinate2D coordinate;
for (int i = 0; i < jsonArray.count; i++)
{
NSDictionary *jsonElement = jsonArray[i];
MKPointAnnotation* marker = [[MKPointAnnotation alloc] init];
marker.title = jsonElement[#"Name"];
marker.subtitle = jsonElement[#"Address"];
coordinate.latitude = [jsonElement [#"Latitude"] doubleValue];
coordinate.longitude = [jsonElement [#"Longitude"] doubleValue];
marker.coordinate = coordinate;
[_locations addObject:marker];
}
[self.mapView addAnnotations:_locations];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *identifier;
{
if (annotation == mapView.userLocation) return nil;
MKAnnotationView *annotationView;
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"blue_pin.png"];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[self.mapView setShowsUserLocation:YES];
}
}
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationCoordinate2D myLocation = [userLocation coordinate];
MKCoordinateRegion zoomRegion = MKCoordinateRegionMakeWithDistance(myLocation, 10000, 10000);
[self.mapView setRegion:zoomRegion animated:YES];
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)InterfaceOrientation
{
return (InterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)Refresh:(id)sender {
}
#end
You can find my solution with comment.
Remove your old data when you refresh or when you got the response.
- (IBAction)action_goToManageDevice:(id)sender
{
[self reloadData];
}
- (void)reloadData
{
// Remove old annotation
[self.mapView removeAnnotations:self.mapView.annotations];
// reload your data
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://sample.name/service.php"];
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
now i find the my current location in simulator
when press button show my current location
but my app located other locations
.h
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate>
#property (nonatomic,retain)MKMapView *mapView;
- (IBAction)myview:(id)sender;
#property (strong, nonatomic) IBOutlet CLLocationManager *locationManger;
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)myview:(id)sender {
_locationManger =[[CLLocationManager alloc]init];
_locationManger.distanceFilter=kCLDistanceFilterNone;
_locationManger.desiredAccuracy=kCLLocationAccuracyHundredMeters;
[_locationManger startUpdatingLocation];
[_mapView setMapType:MKMapTypeStandard];
[_mapView setZoomEnabled:YES];
[_mapView setScrollEnabled:YES];
MKCoordinateRegion region={ {0.0,0.0 },{0.0,0.0}};
region.center.latitude=_locationManger.location.coordinate.latitude;
region.center.longitude=_locationManger.location.coordinate.longitude;
region.span.longitudeDelta=0.007f;
region.span.latitudeDelta=0.007f;
[_mapView setRegion:region animated:YES];
[_mapView setDelegate:sender];
}
#end
i want when button press my current location show in map
use this following link it is very hopeful for you to find the current Location and etc, the link is http://www.appcoda.com/how-to-get-current-location-iphone-user/
Step 1: #import <MobileCoreServices/MobileCoreServices.h> in header file
Step 2: Add delegate CLLocationManagerDelegate
#interface yourViewController : UIViewController<CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
CLLocation *currentLocation;
}
Step 3: Add this code in class file
- (void)viewDidLoad
{
[super viewDidLoad];
[self CurrentLocationIdentifier]; // call this method
}
Step 4: Method to get location
//------------ Current Location Address-----
-(void)CurrentLocationIdentifier
{
//---- For getting current gps location
locationManager = [CLLocationManager new];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
//------
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
currentLocation = [locations objectAtIndex:0];
[locationManager stopUpdatingLocation];
CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
{
if (!(error))
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
NSLog(#"\nCurrent Location Detected\n");
NSLog(#"placemark %#",placemark);
NSString *locatedAt = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
NSString *Address = [[NSString alloc]initWithString:locatedAt];
NSString *Area = [[NSString alloc]initWithString:placemark.locality];
NSString *Country = [[NSString alloc]initWithString:placemark.country];
NSString *CountryArea = [NSString stringWithFormat:#"%#, %#", Area,Country];
NSLog(#"%#",CountryArea);
}
else
{
NSLog(#"Geocode failed with error %#", error);
NSLog(#"\nCurrent Location Not Detected\n");
//return;
CountryArea = NULL;
}
/*---- For more results
placemark.region);
placemark.country);
placemark.locality);
placemark.name);
placemark.ocean);
placemark.postalCode);
placemark.subLocality);
placemark.location);
------*/
}];
}
-(void)getLocationCurrentAddresslatitude:(NSString *)lat andlongitude:(NSString *)longitude
{
NSHTTPURLResponse *response = nil;
NSString *jsonUrlString = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/geocode/json?latlng=%#,%#&key=gfhhfhfhfghfghfhghfghfghDyk&result_type=street_address",lat,longitude];
NSLog(#"%#",jsonUrlString);
NSURL *url = [NSURL URLWithString:[jsonUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
//-- Get request and response though URL
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
//-- JSON Parsing
NSDictionary * rootDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil];
NSArray * result = [rootDictionary objectForKey:#"results"];
NSDictionary *dic=[result objectAtIndex:0];
NSString *address=[dic objectForKey:#"formatted_address"];
self.myAddress.text=address;
}
I made an AR app that recognize image and show the object recognized in an AlertView. In the AlertView I have 2 buttons: Add and Cancel, I'm using the UIAlertViewDelegate to understand which button the user pressed. If the user press the Add button, the object recognized will be stored in an array. I pass this array to another ViewController, in which I set up a TableView. On the bottom of this TableView there's a button "Pay" to go to another ViewController in which I display the total price of the object recognized. From the last ViewController I can press a button to pay the objects I selected by using the AR. Now when I press this button the app close this ViewController and go back to the first ViewController, but the array in which I stored the object that the AR recognized it's full. To delete the content of this array I thought that the best way is to use the delegation methods, so I made this:
PaymentViewController.h
#import <UIKit/UIKit.h>
#protocol PaymentViewControllerDelegate;
#interface PaymentViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *labelTotal;
- (IBAction)buttonClosePaymentVC:(id)sender;
- (IBAction)buttonPay:(id)sender;
#property(nonatomic,strong)NSString *total;
#property(assign) id<PaymentViewControllerDelegate> delegate;
#end
#protocol PaymentViewControllerDelegate <NSObject>
- (void)cleanReportArray;
#end
PaymentViewController.m
#import "PaymentViewController.h"
#interface PaymentViewController () <UIAlertViewDelegate>
#end
#implementation PaymentViewController
#synthesize delegate = _delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.labelTotal.text = self.total;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)buttonClosePaymentVC:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)buttonPay:(id)sender {
NSString *pay = [NSString stringWithFormat:#"Stai per pagare %#, procedi?", self.total];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:pay delegate:self cancelButtonTitle:#"Si" otherButtonTitles:#"No", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
// Procedura per il pagamento e cancellazione del file plist
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"objects.plist"];
NSError *error;
if (![[NSFileManager defaultManager]removeItemAtPath:path error:&error]) {
NSLog(#"Errore: %#", error);
}
__weak UIViewController *vcThatPresentedCurrent = self.presentingViewController;
[self dismissViewControllerAnimated:YES completion:^{
[vcThatPresentedCurrent dismissViewControllerAnimated:YES completion:nil];
}];
[self.delegate cleanReportArray];
}
if (buttonIndex == 1) {
// Non deve far nulla: fa scomparire l'UIAlertView
}
}
Here I post to you the method of the class that will use the delegate:
Interface of the ScannerViewController.m
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
In ViewDidLoad I inserted this rows:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
And in the ScannerViewController.m I implemented the method I declared in PaymentViewController.h:
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
I tested my app on my iPhone, the app works fine until I try to pay the objects I scanned by camera, indeed, I tried to pay the object, but it doesn't clean the array in which I stored the objects scanned.
What's wrong in my code? I used an tutorial on the web to understand better how the delegation method works. I hope you can help me to fix this issue, thank you
UPDATE:
here i will post my ScannerViewController code:
ScannerViewController.h
#import <UIKit/UIKit.h>
#interface ScannerViewController : UIViewController
#end
ScannerViewController.m
#import "ScannerViewController.h"
#import "PaymentViewController.h"
#import "ReportViewController.h"
#import "MSScannerSession.h"
#import "MSResult.h"
#import "XmlReader.h"
static int kMSScanOptions = MS_RESULT_TYPE_IMAGE |
MS_RESULT_TYPE_EAN8 |
MS_RESULT_TYPE_EAN13;
#interface ScannerViewController () <MSScannerSessionDelegate, PaymentViewControllerDelegate, UIActionSheetDelegate, UIAlertViewDelegate>
#property (weak) IBOutlet UIView *videoPreview;
- (IBAction)stopScanner:(id)sender;
#end
#implementation ScannerViewController {
MSScannerSession *_scannerSession;
NSString *nameOfObjectScanned;
XmlReader *reader;
NSMutableArray *arrayObjectAdded;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_scannerSession = [[MSScannerSession alloc] initWithScanner:[MSScanner sharedInstance]];
[_scannerSession setScanOptions:kMSScanOptions];
[_scannerSession setDelegate:self];
}
return self;
}
- (void)session:(MSScannerSession *)scanner didScan:(MSResult *)result {
if (!result) {
return;
}
[_scannerSession pause];
NSString *resultStr = nil;
if (result) {
switch ([result getType]) {
case MS_RESULT_TYPE_IMAGE:
resultStr = [NSString stringWithFormat:#"Immagine trovata: %#", [result getValue]];
break;
case MS_RESULT_TYPE_EAN8:
case MS_RESULT_TYPE_EAN13:
resultStr = [NSString stringWithFormat:#"EAN trovato: %#", [result getValue]];
break;
default:
break;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
UIActionSheet *asView = [[UIActionSheet alloc]initWithTitle:resultStr delegate:self cancelButtonTitle:#"OK" destructiveButtonTitle:nil otherButtonTitles:nil, nil];
asView.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
[asView showInView:self.view];
[self addObjectToList:resultStr];
});
}
- (void)addObjectToList:(NSString *)objectName {
// Ricerca dell'oggetto
NSString *object = [objectName substringFromIndex:18];
if ([object isEqualToString:#"Binario_con_coppia"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_colorati"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Dadi_rossi"]) {
[self showAlert:object];
}
if ([object isEqualToString:#"Bici_da_corsa"]) {
[self showAlert:object];
}
}
- (void)showAlert:(NSString*)name {
name = [name stringByReplacingOccurrencesOfString:#"_" withString:#" "];
nameOfObjectScanned = name;
NSString *message = [NSString stringWithFormat:#"Ho riconosciuto questo oggetto: %#, vuoi aggiungerlo al carrello?", name];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"HelloMS" message:message delegate:self cancelButtonTitle:#"Aggiungi" otherButtonTitles:#"Annulla", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"Aggiungi");
for (int i = 0; i < [reader.objArray count]; i++) {
if ([[reader.objArray[i]objectForKey:#"name"] isEqualToString:nameOfObjectScanned]) {
// Salvo il nome dell'oggetto trovato, il prezzo e la descrizione
NSString *name = [reader.objArray[i]objectForKey:#"name"];
NSString *desc = [reader.objArray[i]objectForKey:#"desc"];
NSString *price = [reader.objArray[i]objectForKey:#"price"];
NSDictionary *newObjectAdded = [[NSDictionary alloc]init];
newObjectAdded = #{#"name": name,
#"desc": desc,
#"price": price};
[arrayObjectAdded addObject:newObjectAdded];
}
}
} else {
NSLog(#"Annulla");
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
[_scannerSession resume];
}
- (void)viewDidLoad
{
[super viewDidLoad];
arrayObjectAdded = [[NSMutableArray alloc]init];
CALayer *videoPreviewLayer = [self.videoPreview layer];
[videoPreviewLayer setMasksToBounds:YES];
CALayer *captureLayer = [_scannerSession previewLayer];
[captureLayer setFrame:[self.videoPreview bounds]];
[videoPreviewLayer insertSublayer:captureLayer below:[[videoPreviewLayer sublayers] objectAtIndex:0]];
reader = [[XmlReader alloc]init];
[reader parseXml];
[_scannerSession startCapture];
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
}
- (void)cleanReportArray {
[arrayObjectAdded removeAllObjects];
}
- (void)dealloc {
[_scannerSession stopCapture];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)stopScanner:(id)sender {
ReportViewController *reportVC = [[ReportViewController alloc]initWithNibName:#"ReportViewController" bundle:nil];
reportVC.reportArray = arrayObjectAdded;
[reportVC setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:reportVC animated:YES completion:nil];
}
#end
To recognize picture I'm using this AR SDK. I hope you can help me to understand where's my issue
Your problem is that in viewDidLoad you have the code:
PaymentViewController *pay = [[PaymentViewController alloc]init];
[pay setDelegate:self];
this is the last thing you do in that method. So the instance of PaymentViewController that you create and set the delegate on is immediately destroyed (by ARC).
You need to modify your code so that you call setDelegate: on the actual instance of PaymentViewController that is presented on screen as this is the instance that needs to use the delegate (it receives the callback from the alert view).
I am quite new to Objective-C and this is the first time I have attempted to implement MVC. I have a model class where l have an NSArray which will be populated with data from a JSON object. I want to populate my UITableView (in my view controller class), with objects from this array.
Please review my code:
Droplets.h
#interface Droplets : NSObject {
NSArray *dropletsArray;
}
// Get droplets data
- (void) getDropletsList;
//Object initilization
- (id) init;
//Public properties
#property (strong, nonatomic) NSArray *dropletsArray; // Used to store the selected JSON data objects
#end
Droplets.m
#define kBgQueue dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define kDigialOceanApiURL [NSURL URLWithString:#"http://inspiredwd.com/api-test.php"] //Droplets API call
#import "Droplets.h"
#interface Droplets ()
//Private Properties
#property (strong, nonatomic) NSMutableData *data; // Used to store all JSON data objects
#end
#implementation Droplets;
#synthesize dropletsArray;
#synthesize data;
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (void) getDropletsList {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = kDigialOceanApiURL; // Predefined Digital Ocean URL API http request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self]; //Should be: [[NSURLConnection alloc]initiWithRequest:request delegate:self]; ...however the instance of NSURLConnection is never used, which results in an "entity unsed" error.
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
data = [[NSMutableData alloc]init]; // mutable data dictionary is allocated and initilized
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData {
[data appendData:theData]; // append 'theData' to the mutable data dictionary
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
//JSON foundation object returns JSON data from a foundation object. Assigned returned data to a dictionary 'json'.
NSDictionary* jsonData = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions error:0];
self.dropletsArray = [jsonData objectForKey:#"droplets"]; //dictionary of arrays
NSLog(#"Droplets %#", self.dropletsArray);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// If the application is unable to connect to The Digital Ocean Server, then display an UIAlertView
UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Unable to connect to The Digital Ocean Server, please ensure that you are connected via either WIFI or 3G." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // Turn of the network activity indicator
}
#end
DropletsList.h
#class Droplets;
#interface DropletsList : UITableViewController
- (Droplets *) modelDroplets;
#end
DropletsList.m
#define RGB(r, g, b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
#interface DropletsList ()
//Private properties
#property (strong, nonatomic) Droplets *modelDroplets;
#property (strong, nonatomic) NSArray *tableData;
#end
#implementation DropletsList
#synthesize tableData;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
NSLog(#"get my data from model");
}
return self;
}
- (Droplets *) modelDroplets
{
if (!_modelDroplets) _modelDroplets = [[Droplets alloc]init];
return _modelDroplets;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_modelDroplets = [[Droplets alloc]init];
self.tableData = [_modelDroplets dropletsArray];
[_modelDroplets getDropletsList];
[self.tableView reloadData]; // reload the droplets table controller
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView {
return 1; // Return the number of sections.
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
return [_modelDroplets.dropletsArray count]; // Return the number of rows in the section.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// The cell identified by "dropletsList", is assiged as the UITableViewCell
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"dropletsList"];
//NSLog(#"Droplets Name: %#",self.dropletsArray);
// The UITableView text label is assigned the contents from 'dropletsArray', with the object key "name"- name of the droplet
cell.textLabel.text=[[tableData objectAtIndex:indexPath.row]objectForKey:#"name"];
// The UITableView text detail label is assigned the contents from 'dropletsArray', with the object key "status"- status of the droplet
cell.detailTextLabel.text=[[tableData objectAtIndex:indexPath.row]objectForKey:#"status"];
//Evalulate the status of each droplet, setting the colour appropriate to the staus
if ([[[tableData objectAtIndex:indexPath.row] objectForKey:#"status"] isEqualToString:#"active"]) {
//Set the detail text label colour
cell.detailTextLabel.textColor = RGB (35,179,0);
}
return cell;
}
#end
Basically my table doesn't populate. Please could someone help?
- (void)viewDidLoad
{
[super viewDidLoad];
_modelDroplets = [[Droplets alloc]init];
self.tableData = [_modelDroplets dropletsArray];
[_modelDroplets getDropletsList];
[self.tableView reloadData]; // reload the droplets table controller
}
In this method you are fetching droplets from a webservice. It is asynchronous, by the time tableView reloads the data it might not have completed fetching the data. You need to have a callback which will reload the tableView on completion of webservice.
EDIT :
Create a class method in Droplets to fetch all data
//Droplets.h
typedef void (^NSArrayBlock)(NSArray * array);
typedef void (^NSErrorBlock)(NSError * error);
//Droplets.m
+ (void)getDropletsWithCompletion:(NSArrayBlock)arrayBlock onError:(NSErrorBlock)errorBlock
{
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:kDigialOceanApiURL];
[urlRequest setHTTPMethod:#"GET"];
[urlRequest setCachePolicy:NSURLCacheStorageNotAllowed];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) {
if (error) {
errorBlock(error);
}else{
NSError *serializationError = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData
options:NSJSONReadingAllowFragments
error:&serializationError];
arrayBlock(json[#"droplets"]);
}
}];
}
//DropletsList.h
- (void)viewDidLoad
{
[super viewDidLoad];
[Droplets getDropletsWithCompletion:^(NSArray *array) {
self.modelDroplets = droplets;
[self.tableView reloadData];
} onError:^(NSError *error) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}];
}
Disclaimer : Tested and verified :)