I have a very annoying issue with code I am working on in xcode for iOS, and it is driving me crazy!
This will take a lot of code explanation, as I need to include a lot of code.
I had a viewcontroller
working, connecting to an online mysql
database, and populating a tableview
. This was all working great.
I then had to duplicate this code, as I want to download from another database and populate a mapview using co-ordinates from another mysql database.
Screen5ViewController.h / Screen5ViewController.m
are the files for the viewcontroller
with the tableview
.
ShopTable.h / ShopTable.m
is the code that handles the downloading of the data from the database.
This was all working.
Screen2ViewController.h / Screen2ViewController.m / MapTable.h / MapTable.m
are the files I duplicated to download from the other database to populate the mapview
.
This doesnt work at all, and doesnt even call the method ("NSLog(@"map table called...");")
- so it doesnt even try to download the data.
I dont understand why this method isnt even called?
The code compiles and runs with no errors and no warnings.
Any help anyone can give would be very much appreciated. I have spent so much time looking over this code and trying everything I can think of!
Screen5ViewController.h
#import <UIKit/UIKit.h>
#import "ShopTable.h"
@interface Screen5ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, ShopTableProtocol> {
}
@property (weak, nonatomic) IBOutlet UITableView *shopTableView;
@end
Screen5ViewController.m
#import "Screen5ViewController.h"
@interface Screen5ViewController () {
ShopTable *_shopTable;
NSArray *_feedItems;
}
@end
@implementation Screen5ViewController
@synthesize
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Screen 5";
// Set this view controller object as the delegate and data source for the table view
self.shopTableView.delegate = self;
self.shopTableView.dataSource = self;
// Create array object and assign it to _feedItems variable
_feedItems = [[NSArray alloc] init];
// Create new ShopTable object and assign it to _shopTable variable
_shopTable = [[ShopTable alloc] init];
// Set this view controller object as the delegate for the home model object
_shopTable.delegate = self;
// Call the download items method of the home model object
[_shopTable downloadItems2];
}
-(void)itemsDownloaded2:(NSArray *)items {
// This delegate method will get called when the items are finished downloading
// Set the downloaded items to the array
_feedItems = items;
// Reload the table view
[self.shopTableView reloadData];
}
#pragma mark Table View Delegate Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of feed items (initially 0)
return _feedItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Retrieve cell
NSString *cellIdentifier = @"shopTableCell";
UITableViewCell *myCell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// Get the location to be shown
Location2 *item = _feedItems[indexPath.row];
// Get references to labels of cell
myCell.textLabel.text = item.name;
myCell.detailTextLabel.text = item.address;
return myCell;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
ShopTable.h
#import <Foundation/Foundation.h>
@protocol ShopTableProtocol <NSObject>
- (void)itemsDownloaded2:(NSArray *)items;
@end
@interface ShopTable : NSObject <NSURLConnectionDataDelegate>
@property (nonatomic, weak) id<ShopTableProtocol> delegate;
- (void)downloadItems2;
@end
@interface Location2 : NSObject
@property (nonatomic, strong) NSString *latitude;
@property (nonatomic, strong) NSString *longitude;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *address;
@end
ShopTable.m
#import "ShopTable.h"
@interface ShopTable() {
NSMutableData *_downloadedData;
}
@end
@implementation ShopTable
- (void)downloadItems2 {
NSLog(@"shop table called...");
// Download the json file
NSURL *jsonFileUrl = [NSURL URLWithString:@"http://www.example.com/shop.php"];
// Create the request
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
// Create the NSURLConnection
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
#pragma mark NSURLConnectionDataProtocol Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// Initialize the data object
_downloadedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the newly downloaded data
[_downloadedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Create an array to store the locations
NSMutableArray *_locations = [[NSMutableArray alloc] init];
// Parse the JSON that came in
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_downloadedData options:NSJSONReadingAllowFragments error:&error];
// Loop through Json objects, create question objects and add them to our questions array
for (int i = 0; i < jsonArray.count; i++) {
NSDictionary *jsonElement = jsonArray[i];
// Create a new location object and set its props to JsonElement properties
Location2 *newLocation = [[Location2 alloc] init];
newLocation.name = jsonElement[@"title"];
newLocation.address = jsonElement[@"description"];
newLocation.latitude = jsonElement[@"Latitude"];
newLocation.longitude = jsonElement[@"Longitude"];
// Add this question to the locations array
[_locations addObject:newLocation];
}
// Ready to notify delegate that data is ready and pass back items
if (self.delegate) {
[self.delegate itemsDownloaded2:_locations];
}
}
@end
@implementation Location2
@end
Screen2ViewController.h
#import <UIKit/UIKit.h>
#import "MapTable.h"
@interface Screen2ViewController : UIViewController <MapTableProtocol> {
}
@end
Screen2ViewController.m
#import "Screen2ViewController.h"
@interface Screen2ViewController () {
MapTable *_mapTable;
NSArray *_feedItems1;
}
@end
@implementation Screen2ViewController
@synthesize
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Screen 2";
NSLog(@"1"); // This is called fine!
// Create array object and assign it to _feedItems variable
_feedItems1 = [[NSArray alloc] init];
NSLog(@"2"); // This is called fine!
// Set this view controller object as the delegate for the home model object
_mapTable.delegate = self;
NSLog(@"3"); // This is called fine!
// Call the download items method of the home model object
[_mapTable downloadItems];
}
NSLog(@"4"); // This is called fine!
-(void)itemsDownloaded:(NSArray *)items {
// This delegate method will get called when the items are finished downloading
// Set the downloaded items to the array
_feedItems1 = items;
NSLog(@"%lu locations downloaded ok!", (unsigned long)_feedItems1.count);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
MapTable.h
#import <Foundation/Foundation.h>
@protocol MapTableProtocol <NSObject>
- (void)itemsDownloaded:(NSArray *)items;
@end
@interface MapTable : NSObject <NSURLConnectionDataDelegate>
@property (nonatomic, weak) id<MapTableProtocol> delegate;
- (void)downloadItems;
@end
@interface Location : NSObject
@property (nonatomic, strong) NSString *latitude;
@property (nonatomic, strong) NSString *longitude;
@property (nonatomic, strong) NSString *name;
@end
MapTable.m
#import "MapTable.h"
@interface MapTable() {
NSMutableData *_downloadedData1;
}
@end
@implementation MapTable
- (void)downloadItems {
NSLog(@"map table called..."); // THIS CODE NEVER GETS CALLED??!!
// Download the json file
NSURL *jsonFileUrl = [NSURL URLWithString:@"http://www.example.com/map.php"];
// Create the request
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
// Create the NSURLConnection
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
#pragma mark NSURLConnectionDataProtocol Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// Initialize the data object
_downloadedData1 = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the newly downloaded data
[_downloadedData1 appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Create an array to store the locations
NSMutableArray *_locations = [[NSMutableArray alloc] init];
// Parse the JSON that came in
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_downloadedData1 options:NSJSONReadingAllowFragments error:&error];
// Loop through Json objects, create question objects and add them to our questions array
for (int i = 0; i < jsonArray.count; i++) {
NSDictionary *jsonElement = jsonArray[i];
// Create a new location object and set its props to JsonElement properties
Location *newLocation = [[Location alloc] init];
newLocation.name = jsonElement[@"firstname"];
newLocation.latitude = jsonElement[@"mylatitude"];
newLocation.longitude = jsonElement[@"mylongitude"];
// Add this question to the locations array
[_locations addObject:newLocation];
}
// Ready to notify delegate that data is ready and pass back items
if (self.delegate) {
[self.delegate itemsDownloaded:_locations];
}
}
@end
@implementation Location
@end
In your Screen2ViewController.h
:
@interface Screen2ViewController : UIViewController <MKMapViewDelegate, MapTableProtocol> {
IBOutlet MKMapView *mapView;
}
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
@end
Your MKMapView
from interface builder is probably linked to the @property
, but everywhere in the Screen2ViewController.m
you are working with mapView
(instance variable which is never initialised) instead of self.mapView
.
Also, compared to Screen5ViewController.m
you are missing MapTable
initialisation in Screen2ViewController
's -viewDidLoad
method:
_mapTable = [[MapTable alloc] init];