can't populate UITableView, source array valid - ios

I can't make my table view show my data, the array has valid data by the NSLog output. I put a breakpoint at the beginning of tableView:cellForRowAtIndexPath: and it never get there. Any ideas why?
#import "ViewController.h"
#import "Ride.h"
#interface ViewController ()
#property (nonatomic, strong) NSMutableData *responseData;
#end
#implementation ViewController
#synthesize rideIds = _rideIds;
#synthesize rideNames = _rideNames;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"viewdidload");
self.responseData = [NSMutableData data];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
// http://www.strava.com/api/v1/segments/229781/efforts?best=true
// Efforts on segment by athlete limited by startDate and endDate
//NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.strava.com/api/v1/segments/229781/efforts?athleteId=11673&startDate=2012-02-01&endDate=2012-02-28"]];
//Leader Board on Segment all Athletes
//NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.strava.com/api/v1/segments/229781/efforts?best=true"]];
//Rides by Athlete
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.strava.com/api/v1/rides?athleteId=10273"]];
//Twitter Example
//NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://api.twitter.com/1/trends"]];
//Efforts by Ride
//NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.strava.com/api/v1/rides/77563/efforts"]];
//Effort Detail
//NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.strava.com/api/v1/efforts/688432"]];
//Google API Call
//NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://maps.googleapis.com/maps/api/place/search/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&sensor=false&key=AIzaSyAbgGH36jnyow0MbJNP4g6INkMXqgKFfHk"]];
/* dispatch_async(dispatch_get_main_queue(),^ {
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
} ); */
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(theConnection){
self.rideIds = [[NSMutableArray alloc]init];
self.rideNames = [[NSMutableArray alloc] init];
} else {
NSLog(#"No Connection");
}
}
//Delegate methods for the NSURLConnection
//In order to download the contents of a URL, an application needs to provide a delegate object that, at a minimum, implements the following delegate methods: connection:didReceiveResponse:, connection:didReceiveData:, connection:didFailWithError: and connectionDidFinishLoading:.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"didReceiveResponse");
//This message can be sent due to server redirects, or in rare cases multi-part MIME documents.
//Each time the delegate receives the connection:didReceiveResponse: message, it should reset any progress indication and discard all previously received data.
[self.responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"didFailWithError");
NSString *errorDescription = [error description];
// NSLog([NSString stringWithFormat:#"Connection failed: %#", errorDescription]);
NSLog(#"Connection failed: %#", errorDescription);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading");
NSLog(#"Succeeded! Received %d bytes of data",[self.responseData length]);
// convert to JSON
NSError *myError = nil;
//NSDictionary *jsonRes = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&myError];
NSDictionary *jsonResult = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&myError];
NSDictionary *jsonRides =[jsonResult objectForKey:#"rides"];
// Show all values coming out of "rides" key
// Store ride id's and names on arrays for later display on tableview
for (NSDictionary *rides in jsonRides) {
[self.rideIds addObject:[rides objectForKey:#"id"]];
NSLog(#"id = %#", [rides objectForKey:#"id"]);
//NSLog(#"%#",self.rideIds);
[self.rideNames addObject:[rides objectForKey:#"name"]];
NSLog(#"name = %#", [rides objectForKey:#"name"]);
//NSLog(#"%#",self.rideNames);
}
NSLog(#"%#",self.rideIds);
NSLog(#"%#",self.rideNames);
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// Show all values coming out of NSKSONSerialization
for(id key in jsonResult) {
id value = [jsonResult objectForKey:key];
NSString *keyAsString = (NSString *)key;
NSString *valueAsString = (NSString *)value;
NSLog(#"key: %#", keyAsString);
NSLog(#"value: %#", valueAsString);
}
// extract specific value...
// NSArray *results = [res objectForKey:#"results"];
/*NSArray *results = [res objectForKey:#"rides"];
for (NSDictionary *result in results) {
NSData *athleteData = [result objectForKey:#"name"];
NSLog(#"Ride name: %#", athleteData);
}*/
/* dispatch_async(dispatch_get_main_queue(),^ {
[self.rideTableView reloadData];
} ); */
[self.rideTableView reloadData];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"tableView:numberOfRowsInSection: ");
//return self.rideIds.count;
NSLog(#"%u",self.rideNames.count);
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"tableView:cellForRowAtIndexPath: ");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if( nil == cell ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text= [self.rideNames objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tv
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tv deselectRowAtIndexPath:indexPath animated:YES];
}
#end
NSLog content:
2012-08-18 18:47:29.497 WebServiceCall[10387:c07] viewdidload
2012-08-18 18:47:29.503 WebServiceCall[10387:c07] tableView:numberOfRowsInSection:
2012-08-18 18:47:29.503 WebServiceCall[10387:c07] 0
2012-08-18 18:47:29.504 WebServiceCall[10387:c07] tableView:cellForRowAtIndexPath:
2012-08-18 18:47:29.506 WebServiceCall[10387:c07] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(0x14b6022 0xeb6cd6 0x14a2d88 0x395d 0xb3c54 0xb43ce 0x9fcbd 0xae6f1 0x57d42 0x14b7e42 0x1d87679 0x1d91579 0x1d164f7 0x1d183f6 0x1da5160 0x17e84 0x18767 0x27183 0x27c38 0x1b634 0x13a0ef5 0x148a195 0x13eeff2 0x13ed8da 0x13ecd84 0x13ecc9b 0x17c65 0x19626 0x22fd 0x2265 0x1)
terminate called throwing an exception(lldb)
UPDATE: It seems that after passing through viewDidLoad it jumps right into tableview:numberOfRowsInSection method skipping all the 4 methods for handling NSURLConnection (where I updated my arrays).
My view controller is both delegate of my NSURLConnection AND my tableView. It seems that it's running first the tableView methods. Any suggestions as to how to make it run the NSURLConnection methods first ?

Two things you could try -- First, log self.rideIds.count in your numberOfRowsInSection method to make sure it's not returning 0. Second, at the end of your connectionDidFinishLoading method, put in a [tableView reloadData] (or whatever the outlet to your table view is), that should take care of the problem of the table view methods being called before your connection is done.
After Edit: The error "-[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array" is being caused by the "return 3" in your numberOfRowsInSection method. When the app starts up the table view will try to populate itself before your connection returns any results, so numberOfRowsInSection should return 0 not 3 the first time through, which it will do if you put back the return self.rideIds.count line. If you do the reloadData at the end of the connection delegate methods, then the array will be populated and the table view should work properly.

Where is tableView:numberOfSectionsInTableView:? Perhaps that is returning 0 although the default is 1 if not set; You also need to set delegate and dataSource on your tableView.

Related

Populating my tableview with parsed json in a string

Very new to iOS, a bit lost on what to do. I actually HAVE all that I need, I just need help putting said information into my tableview now. I am debugging and everything is correct when I hover over the variables in my "init" function, but when I go down to the function that handles the cells something is just not clicking. Very frustrating having the information you need but don't know how to put it where you want.
I hate coming to SO for these kind of questions but I have exhausted all other options. Before posting on here, I have tried everything. I tried to google other projects that I can reference, did not find any that was iOS 7 or relevant to my project. I apologize for this elementary question, and thank you in advance.
MasterViewController.m
#interface MasterViewController () {
__block NSString * jsonString;
}
#end
#implementation MasterViewController
#synthesize coursesController = _coursesController;
-(void)getJSONString
{
jsonString = [JSONHelper JSONgetString:#"http://iam.colum.edu/portfolio/api/course?json=True"];
}
-(void)initCourses
{
[_coursesController.masterCoursesList
removeLastObject];
NSError *coursesError = nil;
NSArray *coursesNameList =
[NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error: &
coursesError];
if(coursesError)
NSLog(#"[%# %#] JSON error: %#", NSStringFromClass([self class]),
NSStringFromSelector(_cmd), coursesError.localizedDescription);
NSArray *coursesNames = [coursesNameList objectAtIndex:0];
for (NSString *courseName in coursesNameList) {
NSString *stringToUse = [courseName substringFromIndex:8];
//initialize variables
NSString *name = courseName;
NSInteger *courseid = 00;
NSString *imageUrl = nil;
//add current building to list
[_coursesController masterCoursesListWithName:name AndcourseID:courseid AndimageURL:imageUrl];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CoursesCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Courses *courseAtIndex = [self.coursesController objectInListAtIndex:indexPath.row];
[[cell textLabel] setText:courseAtIndex.courseName];
return cell;
}
CoursesDataController.m
#interface CoursesDataController()
-(void)initializeDefaultDataList;
#end
#implementation CoursesDataController
#synthesize masterCoursesList = _masterCoursesList;
-(void)initializeDefaultDataList
{
NSMutableArray *coursesList = [[NSMutableArray alloc] init];
Courses *course = [[Courses
alloc]initWithName:#"Loading Now..." AndcourseID:00];
[coursesList addObject:course];
}
-(void)setMasterCoursesList:(NSMutableArray *)newCourseList
{
if(_masterCoursesList != newCourseList)
{
_masterCoursesList = [newCourseList mutableCopy];
}
} //this function is created when you create a NSMutableArray MasterCoursesList
-(id)init
{
if (self = [super init])
{
[self initializeDefaultDataList];
return self;
}
return nil;
}
-(NSUInteger) countOfList
{
return [self.masterCoursesList count];
}
-(Courses *)objectInListAtIndex:(NSInteger)theIndex
{
return [self.masterCoursesList objectAtIndex:theIndex];
}
-(void)masterCoursesListWithName:(NSString *)cName
AndcourseID:(NSInteger *)cID
AndimageURL:(NSString *)cURL
{
Courses *courses;
courses = [[Courses alloc] initWithName:cName
AndcourseID:cID
AndimageURL:cURL];
[self.masterCoursesList addObject:courses];
}
-(void)courseName:(NSString *)cName
AndcourseID:(NSInteger *)cID
{
Courses *courses;
courses = [[Courses alloc] initWithName:cName AndcourseID:cID];
[self.masterCoursesList addObject:courses];
}
#end
CoursesDataController.h
#import <Foundation/Foundation.h>
#class Courses;
#interface CoursesDataController : NSObject
#property(nonatomic, copy) NSMutableArray *
masterCoursesList;
-(NSUInteger) countOfList;
-(Courses *)objectInListAtIndex:(NSInteger)theIndex;
- (void)masterCoursesListWithName:(NSString *)cName
AndcourseID:(NSInteger *)cID
AndimageURL:(NSString *)cURL;
- (void)courseName:(NSString *)cName
AndcourseID:(NSInteger *)cID;
#end
JSONHelper.m
+(NSString *)JSONgetString:(NSString *)query
{
NSString* searchURL = [NSString stringWithFormat:query];
NSError* error = nil; //error for NSUSRLConnection
NSURLResponse* response = nil;
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
NSURL* URL = [NSURL URLWithString:searchURL];
[request setURL:URL];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setTimeoutInterval:30];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error)
{
NSLog(#"Error performing request %#", searchURL);
return 0;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"jsonString:%#", jsonString);
return jsonString;
}
I have a lot of code posted, however there are only a few lines that really matter for my question. When I hover over "name" in the following line of code [_coursesController masterCoursesListWithName:name AndcourseID:courseid AndimageURL:imageUrl];
I get what I need (it loops through each JSON array and displays each one). But in the function that handles my cells, when I hover over courseName it doesn't say anything.
Courses *courseAtIndex = [self.coursesController objectInListAtIndex:indexPath.row];
[[cell textLabel] setText:courseAtIndex.courseName];
EDITS:
numberOfRowsInSection function in MasterViewController.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.coursesController countOfList];
}
Try this,
in CoursesDataController.m
-(void)initializeDefaultDataList
{
self.masterCoursesList = [[NSMutableArray alloc] init];
Courses *course = [[Courses
alloc]initWithName:#"Loading Now..." AndcourseID:00];
[self.masterCoursesList addObject:course];
}

Getting wrong data with NSURLRequest when using multiple url's

In my project i am using 2 api's in same class. and i want to get data using NSURLRequest,in first api i am getting latitude longitude of places and put these latitude longitude on second url for getting distance between these places but i am getting same distance with each places
here is my code.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
currentLocation = newLocation;
if (currentLocation != nil){
NSString *str=[NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=2000&types=%#&sensor=false&key=API Key",currentLocation.coordinate.latitude,currentLocation.coordinate.longitude,strCatText];
[self createTheConnection:str];
//[self createTheConnection1:str1];
arrAllData=[[NSMutableArray alloc]init];
int i;
for (i=0; i<=2; i++)
{
NSString *strname=[[[arr valueForKey:#"results"] objectAtIndex:i] valueForKey:#"name"];
NSString *strvicinity=[[[arr valueForKey:#"results"] objectAtIndex:i] valueForKey:#"vicinity"];
NSString *strRef=[[[arr valueForKey:#"results"]objectAtIndex:i]valueForKey:#"reference"];
NSString *strLat=[[[[[arr valueForKey:#"results"] objectAtIndex:i] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lat"];
NSString *strLng=[[[[[arr valueForKey:#"results"] objectAtIndex:i] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lng"];
int j;
for (j=0; j<=0; j++)
{
NSString *str1=[NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%#,%#&sensor=false&mode=driving",currentLocation.coordinate.latitude,currentLocation.coordinate.longitude,strLat,strLng];
//NSLog(#"%#",str1);
[self createTheConnection1:str1];
// if (![strLat isEqual:#"0"]) {
// strDistance=#"";
NSString *strDistance=[[[[[[arr2 valueForKey:#"routes"] objectAtIndex:0] valueForKey:#"legs"] objectAtIndex:0] valueForKey:#"distance"] valueForKey:#"text"];
// NSLog(#"%#",strDistance);
//}
if(strname == nil){
strname = [NSString stringWithFormat:#"%#", [NSNull null]];
}
if(strvicinity == nil){
strvicinity = [NSString stringWithFormat:#"%#", [NSNull null]];
}
if(strRef == nil){
strRef = [NSString stringWithFormat:#"%#", [NSNull null]];
}
if(strDistance == nil){
strDistance = [NSString stringWithFormat:#"%#", [NSNull null]];
}
if (![strDistance isEqual:#"<null>"]) {
arrdata=[[NSMutableArray alloc]initWithObjects:strname,strvicinity,strRef,strDistance, nil];
strDistance=nil;
[arrAllData addObject:arrdata];
}
}
[tblView reloadData];
}
}
-(void)createTheConnection:(NSString*)strUrl
{
NSMutableURLRequest *request=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:[strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
connections=[[NSURLConnection alloc]initWithRequest:request delegate:self];
if(connections)
{
webData=[NSMutableData data];
}
}
-(void)createTheConnection1:(NSString*)strUrl1
{
NSMutableURLRequest *request1=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:[strUrl1 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
connections1=[[NSURLConnection alloc]initWithRequest:request1 delegate:self];
if(connections1)
{
webData1=[NSMutableData data];
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
// //NSLog(#"%#",error);
self.navigationItem.leftBarButtonItem=nil;
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
if (connection==connections) {
[webData appendData:data];
}
if (connection==connections1) {
[webData1 appendData:data];
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
if (connection==connections) {
[webData setLength:0];
}
if (connection==connections1) {
[webData1 setLength:0];
}
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSError *err;
if (connection==connections) {
arr=[NSJSONSerialization JSONObjectWithData:webData options:NSJSONReadingMutableContainers error:&err];
}
if (connection==connections1) {
arr2=[NSJSONSerialization JSONObjectWithData:webData1 options:NSJSONReadingMutableContainers error:&err];
}
}
-(void)barBtnItem1{
MapViewController *mvc =[self.storyboard instantiateViewControllerWithIdentifier:#"mapview"];
[UIView beginAnimations:#"Start" context:nil];
[UIView setAnimationDuration:0.80];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[self.navigationController pushViewController:mvc animated:YES];
[UIView commitAnimations];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return arrAllData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:#"cell"];
UILabel *lblName=(UILabel*)[cell viewWithTag:100];
UILabel *lblAddress=(UILabel*)[cell viewWithTag:101];
UILabel *lblDistance=(UILabel*)[cell viewWithTag:102];
arrData11=[arrAllData objectAtIndex:indexPath.row];
NSString *strName=[NSString stringWithFormat:#"%#",arrData11[0]];
NSString *strAddress=[NSString stringWithFormat:#"%#",arrData11[1]];
NSString *strDistance1=[NSString stringWithFormat:#"%#",arrData11[3]];
if ([strName isEqual:#"<null>"]) {
// lblName.text=#"Loading...";
// lblAddress.text=#"Loading...";
}
else{
lblName.text=strName;
lblAddress.text=strAddress;
lblDistance.text=strDistance1;
}
return cell;
}
You are creating two connection back to back, when they receive data they are calling the delegates but in you app you didn't wait to get the data from first request and then make the second request. I am pretty sure the distance you are getting is the distance of second lat and long.
Make single request for these data and see which distance you are getting. And try to make request one by one. i.e make first request.. get the data .. then make second request. Because they are using same delegate to initialize the data.
EDIT
I am in mobile so I can not help with you code. I'll give a try..
Method A (take parameter that you need to make a url request) {
//Make request with pair of lat and long and necessary datas
}
(void)connectionDidFinishLoading:(NSURLConnection *)connection{
........
//After getting the data
Call method A with next pair of lat long
You can determine next pair by maintaining a global variable.
}
Let me know it that helps...:)

Cannot reload table view in IOS7

I am a quite new to IOS development and keep having struggle with it. I would like to display phone list which an user has from my server but tableview does not display items. I have got data from server well and I think settings for UItableView is correct. Here is my code:
STKPhoneHolderViewController.h
#import <UIKit/UIKit.h>
#import "STKSimpleHttpClientDelegate.h"
#interface STKPhoneHolderViewController : UITableViewController <UITableViewDataSource, STKSimpleHttpClientDelegate>
#property (strong, nonatomic) IBOutlet UITableView *phoneTable;
#property (strong, nonatomic) NSMutableArray *phoneArray;
#end
STKPhoneHolderViewController.m
#implementation STKPhoneHolderViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.phoneTable.dataSource = self;
self.phoneArray = [[NSMutableArray alloc]init];
[self loadPhoneList];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.phoneArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PhoneCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
STKPhoneHolder *phoneHolder = [self.phoneArray objectAtIndex:indexPath.row];
[cell.textLabel setText:phoneHolder.userName];
return cell;
}
#pragma Custom method
- (void) loadPhoneList
{
self.phoneArray = [[NSMutableArray alloc]init];
STKSimpleHttpClient *client = [[STKSimpleHttpClient alloc]init];
client.delegate = self;
NSString *userId = #"your_id_h";
NSString *sUrl = [NSString stringWithFormat:#"%#%#?userid=%#",
MOBILE_API_URL,
PHONEHOLDER_URI,
userId];
[client send:sUrl data:#""];
}
#pragma STKSimpleHttpClientDelegate
-(void) complete:(STKHttpResult*) result
{
if (result.ok != YES){
[STKUtility alert:result.message];
return;
}
self.phoneArray = (NSMutableArray*)result.result;
for (STKPhoneHolder *holder in self.phoneArray) {
NSLog(#"%#", [holder description]);
}
[self.phoneTable reloadData];
NSLog(#" isMainThread(%d)", [NSThread isMainThread] );
}
#end
STKSimpleHttpClient.m
#import "STKSimpleHttpClient.h"
#import "STKSimpleHttpClientDelegate.h"
#implementation STKSimpleHttpClient
NSMutableData *responseData;
STKHttpResult *httpResult;
void (^completeFunction)(STKHttpResult *);
- (void) send:(NSString*)url
data:(NSString*)data
{
httpResult = [[STKHttpResult alloc]init];
dispatch_async(dispatch_get_main_queue(), ^{
if ( data == nil) return;
//Get request object and set properties
NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: url]];
//set header for JSON request and response
[urlRequest setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[urlRequest setValue:#"application/json" forHTTPHeaderField:#"Accept"];
//set http method to POST
[urlRequest setHTTPMethod:#"POST"];
//set time out
[urlRequest setTimeoutInterval:20];
NSData *body = [data dataUsingEncoding:NSUTF8StringEncoding];
//set request body
urlRequest.HTTPBody = body;
//connect to server
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
if (conn==nil){
//Do something
}
});
}
#pragma mark - NSURLConnection Delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
[responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable noow
NSError *error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
BOOL ok = [[json objectForKey:#"ok"] boolValue];
NSString *message = [json objectForKey:#"message"];
if (ok == NO) {
[httpResult setError:message];
} else {
[httpResult setSuccess:[json objectForKey:#"result"]];
}
if (self.delegate !=nil) {
[self.delegate complete:httpResult];
}
responseData = nil;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
if (self.delegate !=nil) {
[self.delegate complete:[httpResult setError:#"Connection failed."]];
}
}
STKPhoneHolder.m
#import <Foundation/Foundation.h>
#interface STKPhoneHolder : NSObject
#property NSString *deviceId;
#property NSString *userId;
#property NSString *userName;
#property NSString *msn;
- (id) initWithDeviceId:(NSString*)aDeviceId
userId:(NSString*)aUserId
userName:(NSString*)aUserName
msn:(NSString*)aMsn;
#end
Log:
2013-12-17 16:14:23.447 [5323:70b] {
deviceId = 11111;
email = "";
msn = 11111111;
role = "";
userId = aaaaaa;
userName = "Joshua Pak";
}
2013-12-17 16:14:23.448 [5323:70b] {
deviceId = 22222;
email = "";
msn = 2222222;
role = "";
userId = bbbbb;
userName = "Jasdf Pak";
}
2013-12-17 16:14:23.449 Stalker[5323:70b] isMainThread(1)
I can see the log printing phoneArray with two phones in 'complete' method but tableview just display "No record". Tableview does not render again even though I called reloadData method. I made sure that [self.phoneTable reloadData] is called in debugging mode.
What do I have to do more?
Try to call reloadData in main thread
#pragma STKSimpleHttpClientDelegate
-(void) complete:(STKHttpResult*) result
{
if (result.ok != YES){
[STKUtility alert:result.message];
return;
}
self.phoneArray = (NSMutableArray*)result.result;
for (STKPhoneHolder *holder in self.phoneArray) {
NSLog(#"%#", [holder description]);
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.phoneTable reloadData];
}
}
Or you can use performSelectorOnMainThread
[self.phoneTable performSelectorOnMainThread:#selector(reloadData)
withObject:nil
waitUntilDone:NO];
I am guessing STKSimpleHttpClient class is calling complete delegate function on different thread, all user interface interaction suppose to be called from main thread.
Try this code to see which thread you are in from the complete delegate function
NSLog(#" isMainThread(%d)", [NSThread isMainThread] );
check this. does the code load the tableview before you get information from web services. if so then write the statement [tableview Reload]; next to the web services information getting process. This will help
It's not necessary to specify the number of sections, but you might want to do it with this code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
I see you're using a Table View Controller, which already has a tableView reference self.tableView.
Like #rdelmar said, you could use that reference instead of your phoneTable:
[[self tableView] setDataSource:self];
[[self tableView] setDelegate:self];
[[self tableView] reloadData];

Lack of Internet Connection Stops Cells from Being Created

I am creating an app that takes a JSON text from a server and translates it into a match schedule for a robotics tournament. I have custom cells that are filled with the data I receive from the site and they display the data for each individual match just fine. The problem is that when I put the matches into a .plist file ("data.plist") so that once the internet connection is established initially, the user doesn't necessarily need to reconnect to the internet once the app is killed in order to view the match schedule for the day. My code works perfectly until I don't connect to the internet. For some reason, the app never goes into the function that creates the cells once the internet connection fails. Please help!! Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
aRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://jrl.teamdriven.us/source/scripts/getElimMatchResultsJSON.php"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
aConnection = [[NSURLConnection alloc] initWithRequest:aRequest delegate:self];
if(aConnection){
receivedData = [NSMutableData data];
}
else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Connection!!" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
jrlDirectory = [paths objectAtIndex:0];
path = [jrlDirectory stringByAppendingPathComponent:#"data.plist"];
if (![[NSFileManager defaultManager] fileExistsAtPath:#"data.plist"]) {
[[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle]pathForResource:#"data" ofType:#"plist"] toPath:path error:nil];
}
dataDict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
// Prevents data from repeating itself
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[receivedData appendData: data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Connection Failed" message:nil delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
NSLog(#"Connection failed! Error - %# %#", [error localizedDescription], [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Success! Received %d bits of data", [receivedData length]);
// Must allocate and initialize all mutable arrays before changing them
sweet16 = [[NSMutableArray alloc]init];
quarterfinals = [[NSMutableArray alloc]init];
semi = [[NSMutableArray alloc]init];
finals = [[NSMutableArray alloc]init];
dict = [[NSMutableDictionary alloc]init];
// The error is created and can be referred to if the code screws up (example in the "if(dict)" loop)
NSError *error;
dict = [NSJSONSerialization JSONObjectWithData:receivedData options:NSJSONReadingMutableLeaves error:&error];
matchNames = [[dict objectForKey:#"ElimMatchListResults"]allKeys];
matchNames = [matchNames sortedArrayUsingSelector:#selector(compare:)];
// Categorize the matches based on the first two letters of their match names
for (NSString *name in matchNames) {
if([[name substringToIndex:2]isEqual:#"16"]){
[sweet16 insertObject:[[dict objectForKey:#"ElimMatchListResults"] objectForKey:name] atIndex:sweet16.count];
}
else if([[name substringToIndex:2]isEqual:#"Q."]){
[quarterfinals insertObject:[[dict objectForKey:#"ElimMatchListResults"]objectForKey:name] atIndex:quarterfinals.count];
}
else if([[name substringToIndex:2]isEqual:#"S."]){
[semi insertObject:[[dict objectForKey:#"ElimMatchListResults"]objectForKey:name] atIndex:semi.count];
}
else if([[name substringToIndex:2]isEqual:#"F."]){
[finals insertObject:[[dict objectForKey:#"ElimMatchListResults"]objectForKey:name] atIndex:finals.count];
}
}
headers = [NSArray arrayWithObjects:#"Sweet 16", #"Quarterfinals", #"Semifinals", #"Finals", nil];
sections = [NSArray arrayWithObjects:sweet16, quarterfinals, semi, finals, nil];
// If the dictionary "dict" gets filled with data...
if (dict) {
[[self tableView]setDelegate:self];
[[self tableView]setDataSource:self];
// Now uses data storage so that the user only needs to initially connect to the internet and then they can keep the schedule afterwords
[dataDict setObject: [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithArray:sections], #"sections",
[NSArray arrayWithArray:headers], #"headers",
nil]
forKey:#"Matches"];
[dataDict writeToFile:path atomically:YES];
}
else{
NSLog(#"%#", error);
}
}
// Set the number of sections based on how many arrays the sections array has within it
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] count];
}
// Set the number of rows in each individual section based on the amount of objects in each array
// within the sections array
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:section] count];
}
// Set headers of sections from the "headers" array
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
return [[[dataDict objectForKey:#"Matches"] objectForKey:#"headers"] objectAtIndex:section];
}
// Create cells as the user scrolls
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"Entered Final Loop");
static NSString *cellIdentifier = #"Cell";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(!cell){
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.matchNum.text = [[[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"MatchID"];
cell.red1.text = [NSString stringWithFormat:#"%#",[[[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"Red 1"]];
cell.red2.text = [NSString stringWithFormat:#"%#",[[[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"Red 2"]];
cell.redScore.text = [NSString stringWithFormat:#"%#", [[[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"Red Score"]];
cell.blue1.text = [NSString stringWithFormat:#"%#",[[[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"Blue 1"]];
cell.blue2.text = [NSString stringWithFormat:#"%#",[[[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"Blue 2"]];
cell.bluescore.text = [NSString stringWithFormat:#"%#", [[[[[dataDict objectForKey:#"Matches"] objectForKey:#"sections"] objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"Blue Score"]];
return cell;
}
I apologize for the lengthy code, I'm just trying to make sure I got all the details in. Please ask any questions you need to in order to clarify, I'm just really stuck and flustered right now as to why it never enters the function that creates cells if it doesn't have an internet connection.
A couple of reactions:
Your fileExistsAtPath doesn't look right. Surely you should have fully qualified path, e.g.:
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
[[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle]pathForResource:#"data" ofType:#"plist"] toPath:path error:nil];
}
I'd also probably suggest you check the success of copyItemAtPath (either the return value or use the error parameter).
I assume you know that the data.plist will never be successfully refreshed before viewDidLoad finishes (because the connection is initiated asynchronously and you return immediately from initWithRequest). This code is just loading the last data.plist values while retrieving the new data proceeds (the previous error notwithstanding). Is that your expectation?
On top of my prior point, your connectionDidFinishLoading does not appear to be issuing a reloadData call for the table, so it seems like you'll always see the previous data. When the connection is done, connectionDidFinishLoading should call reloadData for the UITableView.
Minor, unrelated detail, but I'd probably initialize receivedData in the NSURLConnectionDataDelegate method didReceiveResponse (and only if that response was successful, too). It doesn't really belong in viewDidLoad.
I might also encourage you to check for failure of JSONObjectWithData. Some networking failures manifest themselves as a successful NSURLConnection request that returns an HTML page (!) reporting an error. That HTML page will fail JSONObjectWithData processing. You might want to abort your parsing routine if JSONObjectWithData returns nil or if the error object is not nil.
Found my solution. The
[[self tableView]setDelegate:self];
[[self tableView]setDataSource:self];
Was only located in the "connectionDidFinishLoading:" function, so the data sources were never set if there was no internet connection.
I really appreciated everyone's help in this problem and I have edited a lot of my code to make it work better based off of those suggestions. Thanks!

how to store NSString in Stack

I create stack class in my program that I want store NSString value in that.
this is stack class :
#interface Stack : NSObject
- (void)push:(id)obj;
- (id)pop;
- (BOOL)isEmpty;
#end
#implementation Stack
{
NSMutableArray *stack;
}
- (id)init
{
self = [super init];
if(self!= nil){
stack = [[NSMutableArray alloc] init];
}
return self;
}
- (void)push:(id)obj
{
[stack addObject:obj];
}
- (id)pop
{
id lastobj = [stack lastObject];
[stack removeLastObject];
return lastobj;
}
- (BOOL)isEmpty
{
return stack.count == 0;
}
#end
also I have another class with name : TableViewController
I want when to click on cell in TableViewController store cell's id that receive from URL
this is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// I want that xCode value with xCode2 value push in stack
NSLog(#"Row in Tab : %d",indexPath.row);
if ([Folder containsObject:[All objectAtIndex:indexPath.row]]) {
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://192.168.1.%d/mamal/filemanager.php?dir=%#&folder=%d&id",IP,xCode,indexPath.row]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response = nil;
NSError *err = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *responseString = [[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUTF8StringEncoding];
xCode2 = responseString; //this is new cell's id.I want to push this value in stack
NSLog(#"xcode : %#", xCode2);
[self performSegueWithIdentifier:#"segue4" sender:self];
}
else
{
[self performSegueWithIdentifier:#"segue3" sender:self];
}
}
in top code I want when to click on cell push two value in stack (xCode & xCode2) but I dont know about to use of stack.
you need a variable that holds your stack.. i'd make it a member var:
#implementation TableViewController {
Stack *_stack;
}
...
then when the cell is clicked, push the value
...
if(!_stack)
_stack = [[Stack alloc] init];
[_stack push:xcode2];
...
In addition to what Daij-Djan has suggested, do the following:
#interface Stack : NSMutableArray
- (void)push:(id)obj;
- (id)pop;
- (BOOL)isEmpty;
#end
#implementation Stack
- (id)init
{
self = [super init];
if(self!= nil){
// Perform any initialization here. If you don't then there is no point in implementing init at all.
}
return self;
}
- (void)push:(id)obj
{
[self addObject:obj];
}
- (id)pop
{
id lastobj = [self lastObject];
[self removeLastObject];
return lastobj;
}
- (BOOL)isEmpty
{
return [self count] == 0;
}
#end

Resources