I am getting questions from a server using a php script. I am setting the number of cells according to the number of questions, but when I write to the cells, it only outputs 1 question. If I use a for loop, the cells are blank, but if I set the number it repeats the same question according to how many questions are in the database. Heres the code:
NSString *numOfQuestionsURL = #"http://**.***.**.**/count.php";
NSData *dataURLforSize = [NSData dataWithContentsOfURL:[NSURL URLWithString: numOfQuestionsURL]];
NSString *serverOutputforSize = [[NSString alloc] initWithData:dataURLforSize encoding:NSASCIIStringEncoding];
int numOfQuestions = [serverOutputforSize intValue];
for(int i = 0; i <= numOfQuestions; i++)
{
_hostStr = #"http://**.***.**.**/getQuestion.php?num=";
_appendString = [[NSNumber numberWithInt:i] stringValue];
_hostStr = [_hostStr stringByAppendingString: _appendString];
}
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString: _hostStr]];
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding:NSASCIIStringEncoding];
result.textLabel.text = serverOutput;
_appendString = [[NSNumber numberWithInt:i] stringValue]; is where you tell the script what question you want to retrieve.
you need to use this code like this
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
NSString *numOfQuestionsURL = #"http://**.***.**.**/count.php";
NSData *dataURLforSize = [NSData dataWithContentsOfURL:[NSURL URLWithString: numOfQuestionsURL]];
NSString *serverOutputforSize = [[NSString alloc] initWithData:dataURLforSize encoding:NSASCIIStringEncoding];
return [serverOutputforSize intValue];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//make cell
_hostStr = #"http://**.***.**.**/getQuestion.php?num=";
_appendString = [[NSNumber numberWithInt:indexPath.row] stringValue];
_hostStr = [_hostStr stringByAppendingString: _appendString];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString: _hostStr]];
NSString *serverOutput = [[NSString alloc] initWithData:dataURL encoding:NSASCIIStringEncoding];
cell.textLabel.text = serverOutput;
return cell;
}
Also you can load data in background and maintain an array of question and populate in table.that makes your table smooth . currently your table behaves jerky.
Related
I have a table view and until now I fill the table with spelled numbers like this:
- (NSMutableArray *)data {
if(!_data){
_data = [[NSMutableArray alloc] init];
// spelled numbers
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterSpellOutStyle;
for(int i = 0; i < 20; i++){
NSNumber *thisNumber = [NSNumber numberWithInt:i];
NSString *spelledOutNumber = [formatter stringFromNumber:thisNumber];
[_data addObject:spelledOutNumber];
}
}
return _data;
}
But how can I fill the table now with dynamic items from a database?
This is how I get the data from database:
NSURLSession *session = [NSURLSession sharedSession];
NSString *url = [NSString stringWithFormat:#"http://www.example.net/iOS/game/getData.php"];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSString *errorCode = [json valueForKey:#"error"];
if([errorCode isEqualToString:#"e0"]){
NSArray *jsondata = [json objectForKey:#"data"];
for (int i = 0; i < [jsondata count]; i++) {
NSString *name = [[jsondata objectAtIndex:i] objectForKey:#"name"];
[_data addObject:name];
}
}
}];
[dataTask resume];
But how can I load this data now to the table view? If I just put the database code to the data method it doesnt work, because the database code is asynchron. Can someone help me with it?
Edit:
Here are the data methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel.text = [self.data objectAtIndex:indexPath.row];
return cell;
}
In my iOS app I've a class that performs a web request to get an array of informations located in mySQL DB. In this class I've a method that do this taking as input a mySQL query:
- (NSMutableArray *) myreq:(NSString *)query{
// Create NSData object
NSData *dataQuery = [query
dataUsingEncoding:NSUTF8StringEncoding];
// Get NSString from NSData object in Base64
NSString *base64EncodedQuery = [dataQuery base64EncodedStringWithOptions:0];
// Print the Base64 encoded string
NSLog(#"Encoded: %#", base64EncodedQuery);
NSMutableString *strURL = [NSMutableString stringWithFormat:#"http://…=%#“,base64EncodedQuery];
[strURL setString:[strURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:dataURL
options:kNilOptions
error:&error];
NSMutableArray *results = [[NSMutableArray alloc] init];
int numRow = 0;
for (NSArray *arrow in json) {
[results addObjectsFromArray:arrow];
numRow++;
}
return results;
}
This method send a query to a php script that perform immediately this query to MySQL DB and get a json with results. I translate the json in this method and finally return an array with results.
I call myreq in a method
- (void)downloadScope{
_arrID = [[NSMutableArray alloc] init];
_arrIDUsers = [[NSMutableArray alloc] init];
_arrUsernames = [[NSMutableArray alloc] init];
_arrPictures = [[NSMutableArray alloc] init];
[myQueue addOperation:[NSBlockOperation blockOperationWithBlock: ^{
query = #"SELECT ID FROM mytable”;
[_arrID addObjectsFromArray:[self myreq:query]];
for (int i = 0; i < [_arrID count]; i++) {
NSArray *tempArray = [[NSArray alloc] initWithArray:[self myreq:[NSString stringWithFormat:#"SELECT IDUsr,usrn, pictureaddress FROM mytable WHERE ID = %#",_arrID[i]]]];
[_arrIDUsers insertObject:tempArray[0] atIndex:i];
[_arrUsernames insertObject:tempArray[2] atIndex:i];
[_arrPictures insertObject:tempArray[2] atIndex:i];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.tableView reloadData];
}];
}
}]];
[myQueue setSuspended:NO];
}
In tableView I create cells in this way (using SDWebImage):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Identificatore di cella
NSString *identifier = #“cellmy”;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.backgroundColor = nil;
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
NSString *username = [self.arrUsernames objectAtIndex:indexPath.row];
UILabel *cellLabelUsername = (UILabel *)[cell viewWithTag:2];
cellLabelUsername.text = [username uppercaseString];
UIImageView *cellImageProfileSnap = (UIImageView *)[cell viewWithTag:5];
[cellImageProfileSnap sd_setImageWithURL:[NSURL URLWithString:[_arrPictures objectAtIndex:indexPath.row]] placeholderImage:[UIImage imageNamed:#“…”]];
}
In viewDidLoad I initialize my NSOperationQueue (defined in my interface):
myQueue = [[NSOperationQueue alloc] init];
[myQueue setMaxConcurrentOperationCount:100];
[myQueue setName:#"com.sada"];
My goal is to make everything faster because the loading in tableView is slow and I think that is not dependent on SDWebImage. Please help me
I having a bit difficulty loading images from a json file into UIImage - Table Cells in Xcode. I tried to load the images from the server into a NSArray then populating the table view UIImage cells. Is there something that I am missing here?
Image are located on a SQL server.
Thanks for the help.
Here is the server output from the PHP into Xcode. (cover_image)
(
"13497074790148.jpeg",
"13494650900147.png",
"13494606630147.png",
"13494605220147.jpeg",
"13494602920147.jpeg",
"13494601850147.jpeg",
"13491916300147.jpeg"
)
Here is the code in Xcode
NSArray *itemsimages = [[NSArray alloc]initWithArray:[results valueForKeyPath:#"cover_image"]];
self.itemImages = itemsimages;
Here is the code in table cells
UIImage *imageitm = [UIImage imageNamed: [self.itemImages objectAtIndex: [indexPath row]]];
cell.itmImage.image = imageitm;
return cell;
You don't have those images stored locally so it doesn't have any images to display. I suggest using SDWebImage to provide asyncronous image loading from remote location + caching mechanism.
-(void) viewDidLoad
{
NSURL *url = [NSURL URLWithString:#"YOUR URL"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSMutableArray *img = [[NSMutableArray alloc]init];
NSArray *websiteDetails = (NSArray *) [json objectForKey:#"logos"];
for(int count=0; count<[websiteDetails count]; count++)
{
NSDictionary *websiteInfo = (NSDictionary *) [websiteDetails objectAtIndex:count];
imagefile = (NSString *) [websiteInfo objectForKey:#"image_file"];
if([imagefile length]>0)
{
NSLog(#"Imagefile URL is: %#",imagefile);
[img addObject:imagefile];
}
}
//NSarray listofURL
listofURL = img;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
NSURL *url = [NSURL URLWithString:[listofURL objectAtIndex:indexPath.row]];
NSData *image = [[NSData alloc] initWithContentsOfURL:url];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData:image];
});
});
}
return cell;
}
You need to have a proper url in json response or you can store the common part of the url in the code itself and append it later with the image name returned from server.
I did as follows in the same condition
__autoreleasing NSError* error = nil;
id result = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSDictionary *dict = ((NSDictionary *) result)[#"result"];
NSString *url = dict[#"imageURL"];
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[_buttonImageView setImage:image forState:UIControlStateNormal];
where data is the response returned from server.
I tried for loops etc.. but nothing seem to work. I have a textfield and once I hit save, I puts the text in a table cell, If I do it again, the previous entry gets replaced. Basically, I can't seem to add another cell unless I manually addObject to the array. The data get pulled properly I used NSLog and the data saves as well.
I think the problem is here somewhere:
NSFileManager *filemgr;
NSString *docsDir;
NSArray *dirPaths;
filemgr = [NSFileManager defaultManager];
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the data file
datafilePath = [[NSString alloc] initWithString: [docsDir
stringByAppendingPathComponent: #"data.archive"]];
tablesubtitles = [[NSMutableArray alloc]init];
tabledata = [[NSMutableArray alloc] init];
// Check if the file already exists
if ([filemgr fileExistsAtPath: datafilePath])
{
NSMutableArray *dataArray;
dataArray = [NSKeyedUnarchiver
unarchiveObjectWithFile: datafilePath];
titlestring = [dataArray objectAtIndex:0 ];
detailsstring = [dataArray objectAtIndex:1];
[tabledata addObject:titlestring];
[tablesubtitles addObject:detailsstring];
}
here is the other method for the actual table:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"homeworkcell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"homework"];
}
NSString *cellValue = [tabledata objectAtIndex:indexPath.row];
NSString *subtitle = [tablesubtitles objectAtIndex:indexPath.row];
cell.textLabel.text= cellValue;
cell.detailTextLabel.text= subtitle;
cell.textLabel.font = [UIFont systemFontOfSize:14.0];
cell.textLabel.backgroundColor = [ UIColor clearColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
// Configure the cell.
//-----------------------------------------START----------------------------Set image of cell----
cellImage = [UIImage imageNamed:#"checkboxblank.png"];
cell.imageView.image = cellImage;
//--------------------------------------------END---------------------------end set image of cell--
return cell;
}
here is where I'm saving the data:
NSMutableArray *contactArray;
contactArray = [[NSMutableArray alloc] init];
[contactArray addObject:titlefield.text];
[contactArray addObject:detailstextfield.text];
[contactArray addObject:date ];
[NSKeyedArchiver archiveRootObject:
contactArray toFile:datafilePath];
Do you recreate each time table data model?
tablesubtitles = [[NSMutableArray alloc]init];
tabledata = [[NSMutableArray alloc] init];
You should make class variables for this.
I made some test with the UISearchDisplayController and I found some strange behavior I can not explain properly.
Please take a look at the following code:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return numOfRecords;
}
- (NSArray*) search:(NSString*)query {
// Prepare URL request to download statuses from Twitter
NSString *urlString = [NSString stringWithFormat:#"http://someaddress/search.ac?term=%#", query];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSArray *parsedResult = [json_string JSONValue];
return parsedResult;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellID = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
int i = [indexPath row];
if ( i >= [searchResult count] ) return cell;
NSString *res = [searchResult objectAtIndex:i];
[[cell textLabel] setText:res];
return cell;
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// WEB Request
NSArray *entries = [self search:searchString];
numOfRecords = [entries count];
NSMutableArray *entryTitles = [[NSMutableArray alloc] init];
for (int i=0; i<numOfRecords; i++) {
NSDictionary *entry = [entries objectAtIndex:i];
[entryTitles addObject:[entry objectForKey:#"title"]];
}
searchResult = entryTitles;
return YES;
}
The searchResult variable is a member variable of type NSArray. This code works fine, however if I change the assignment of searchResult to
searchResult = [NSArray arrayWithArray: entryTitles];
The program crashes after typing the second letter in the search field with a EXC_BAD_ACCESS.
Can somebody explain what is the problem that causes this error?
You probably just need to retain it:
searchResult = [[NSArray arrayWithArray: entryTitles] retain];
You need to do this because arrayWithArray just creates an autoreleased object that will be released in the near future. You need to add your retain to take ownership.
Once you've taken ownership, don't forget to release it somewhere.
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// WEB Request
NSArray *entries = [self search:searchString];
[searchResult autorelease];
searchResult = [[entries valueForKeyPath:"#unionOfObjects.title"] retain];
return YES;
}
I ran across the same issue. My problem was that in cellForRowAtIndexPath I was releasing the object in the search results array after loading the string value into the cell for display.
Consequently, when I tried to search for anything it immediately crashed.
Check to make sure you aren't releasing the objects that you are searching against.