I'm building an application with an autocomplete UITableView from this tutorial. I have the autocomplete functionality working properly, but I would like the UITableView-autocomplete drop down to disappear when the word is clicked on or when it is touched up outside. I'm not sure how to set up a delegate when the object is set up programmatically. I've only done this using the interface builder.
.h
#interface slrpViewController : UIViewController<UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
{
NSMutableArray *dataArray;
NSMutableData *receivedData;
NSMutableArray *pastUrls;
NSMutableArray *autocompleteUrls;
UITableView *autocompleteTableView;
}
#property(nonatomic, retain) IBOutlet UITextField *eWordEntered;
#property (nonatomic, retain) NSMutableArray *pastUrls;
#property (nonatomic, retain) NSMutableArray *autocompleteUrls;
#property (retain, nonatomic) NSMutableData *responseData;
#property (nonatomic, retain) UITableView *autocompleteTableView;
-(void)setReceivedData:(NSMutableData*)pReceivedData;
-(NSMutableData *) getReceivedData;
-(void) getAutoCompleteArray;
-(void)searchAutocompleteEntriesWithSubstring:(NSString *)substring;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self getAutoCompleteArray];
pastUrls = [[NSMutableArray alloc] init];
NSLog(#"In the viewDidLoad and pasturl is: %#", self.pastUrls);
self.autocompleteUrls = [[NSMutableArray alloc] init];
autocompleteTableView = [[UITableView alloc] initWithFrame:CGRectMake(210, 225, 310, 120) style:UITableViewStylePlain];
self.autocompleteTableView.delegate = self;
self.autocompleteTableView.dataSource = self;
autocompleteTableView.scrollEnabled = YES;
autocompleteTableView.hidden = YES;
[self.view addSubview:autocompleteTableView];
-(void)setReceivedData:(NSMutableData*)pReceivedData
{
receivedData = pReceivedData;
}
-(NSMutableData *) getReceivedData{
return receivedData;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *e = nil;
NSError *error = nil;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: receivedData options: NSJSONReadingMutableContainers error: &e];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:receivedData
options:kNilOptions
error:&error];
seneca_word.ids = [jsonDict objectForKey:#"ids"];
NSArray *array_ids = [jsonDict objectForKey:#"ids"];
NSString *ids = array_ids[0];
seneca_word.ids = ids;
for (id key in jsonDict)
{
NSLog(#"key: %#, value: %#", key, [jsonDict objectForKey:key]);
NSLog(#"The value of bases by itself is: %#", [jsonDict objectForKey:#"bases"]);
}
if (!jsonArray)
{
NSLog(#"Error parsing JSON: %#", e);
}
else
{
if([jsonDict objectForKey:#"english"] != nil){
pastUrls = [jsonDict objectForKey:#"bases"];
}
else{
//Some of JSON object that I don't want to use here
}//else
}//(void)connectionDidFinishLoading
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring {
[autocompleteUrls removeAllObjects];
for(NSString *curString in pastUrls) {
NSRange substringRange = [curString rangeOfString:substring];
if (substringRange.location == 0) {
[autocompleteUrls addObject:curString];
}
}
[autocompleteTableView reloadData];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
autocompleteTableView.hidden = NO;
NSString *substring = [NSString stringWithString:textField.text];
substring = [substring stringByReplacingCharactersInRange:range withString:string];
[self searchAutocompleteEntriesWithSubstring:substring];
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section {
return autocompleteUrls.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
static NSString *AutoCompleteRowIdentifier = #"AutoCompleteRowIdentifier";
cell = [tableView dequeueReusableCellWithIdentifier:AutoCompleteRowIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AutoCompleteRowIdentifier];
}
cell.textLabel.text = [autocompleteUrls objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
self.eWordEntered.text = selectedCell.textLabel.text;
if(tableView == autocompleteTableView){
//The autocomplete table view is the one that fired the didSelect delegate method
//So hide the autocomplete table.
//do whatever else you need to do to empty the autocompleteTableView's data source
//or/and simply hide the table after that
[autocompleteTableView setHidden:YES];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//When the user clicks outside of the uitableview it will disappear
[autocompleteTableView setHidden:YES];
}
As you can see I populate the autocomplete UITableView with JSON data that I'm getting from a RESTful API.
I'm getting the warning, Assigning to 'id<UITableViewDelegate>' from incompatible type 'ViewController *const __strong' for the lines:
self.autocompleteTableView.delegate = self;
self.autocompleteTableView.dataSource = self;
I imagine once I get the delegate stuff sorted out I'll be able to do what I want. I did some research and tried to create a delegate class but wasn't able to get that solution working. I'm not even sure if that's the right way to go about this as I usually do this stuff by interface builder and not programmatically. Any direction or help is greatly appreciated. Thanks!
You should be using the tableView's didSelectCellAtIndexPathRow delegate method to identify user taps on a cell from a tableView. It's ok if you created your tableView progammatically.
Simply make sure the UIViewController conforms to the UITableViewDelegate and UITableViewDataSource` protocols.
make sure you set the tableView's delegate and dataSource property to self.
Implement the didSelectCellAtIndexPathRow delegate method in your viewController's .m file like so:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
}
Then inside that delegate method you need to help detect from which tableView your didSelect method got fired from as you only want to hide the autocomplete table when the user selects a cell from that table. So you do a simple tableView check like so:
if(tableView == autocompleteTableView){
//The autocomplete table view is the one that fired the didSelect delegate method
//So hide the autocomplete table.
//do whatever else you need to do to empty the autocompleteTableView's data source
//or/and simply hide the table after that
[autocompleteTableView setHidden:YES];
}
You probably also want to make sure that you set the autocompleteTableView hidden property to NO when the user types in something in the textfield so that the auto complete can show appear again.
And thats all buddy.
try setting self.autocompleteTableView.hidden = YES;
Related
Good afternoon,
I'm trying to use a TableView Controller to display X number of items from my MySQL database but I'm a little bit lost at the moment.
I have another project where I can show the data using JSON output data, but I don't know how to add that code to my project in order to show the data from my database. That's the code I used:
#implementation HomeModel
- (void)downloadItems
{
// Download the json file
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://website.com/service.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
Location *newLocation = [[Location alloc] init];
newLocation.name = jsonElement[#"user"];
newLocation.address = jsonElement[#"imagen"];
newLocation.latitude = jsonElement[#"date"];
// 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
Currently that's my code:
TableViewController.m
#import "CarTableViewController.h"
#import "CarTableViewCell.h"
#import "CarTableViewController.h"
#import "CarDetailViewController.h"
#implementation CarTableViewController
#synthesize carMakes = _carMakes;
#synthesize carModels = _carModels;
#synthesize carImages = _carImages;
- (void)viewDidLoad
{
[super viewDidLoad];
self.carMakes = [[NSArray alloc]
initWithObjects:#"Chevy",
#"BMW",
#"Toyota",
#"Volvo",
#"Smart", nil];
self.carModels = [[NSArray alloc]
initWithObjects:#"Volt",
#"Mini",
#"Venza",
#"S60",
#"Fortwo", nil];
self.carImages = [[NSArray alloc]
initWithObjects:#"chevy_volt.jpg",
#"mini_clubman.jpg",
#"toyota_venza.jpg",
#"volvo_s60.jpg",
#"smart_fortwo.jpg", nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.carModels count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"carTableCell";
CarTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CarTableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.makeLabel.text = [self.carMakes
objectAtIndex: [indexPath row]];
cell.modelLabel.text = [self.carModels
objectAtIndex:[indexPath row]];
UIImage *carPhoto = [UIImage imageNamed:
[self.carImages objectAtIndex: [indexPath row]]];
cell.carImage.image = carPhoto;
return cell;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowCarDetails"])
{
CarDetailViewController *detailViewController =
[segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView
indexPathForSelectedRow];
detailViewController.carDetailModel = [[NSArray alloc]
initWithObjects: [self.carMakes
objectAtIndex:[myIndexPath row]],
[self.carModels objectAtIndex:[myIndexPath row]],
[self.carImages objectAtIndex:[myIndexPath row]],
nil];
}
}
#end
TableViewController.h
#import <UIKit/UIKit.h>
#interface CarTableViewController : UITableViewController
#property (nonatomic, strong) NSArray *carImages;
#property (nonatomic, strong) NSArray *carMakes;
#property (nonatomic, strong) NSArray *carModels;
#end
How can I add the first code (results from my database) to the other project? I'm lost at the moment and I will appreciate a lot if you can give me some light on this problem, because I want to edit the info from the storyboard as I have in the second project.
Thanks in advance.
Regards.
Thanks in advance.
It's because you don't connect to your database directly from your iphone. In general ou have a web service (also call API) for expose your data (in JSON format for example). So you have to build an API, in PHP, Ruby or Node, for expose the data of your database and access it.
EDIT:
What i see is in your HomeModel, you can set a delegate, this delegate have a function itemsDownloaded where you pass the data get from your API.
So you want your CarTableViewController to be that delegate for receive those data.
First you have to have an object HomeModel, in your TableViewController.h add:
#property (strong, nonatomic) HomeModel *homeModel;
Now you have to call the code that get the data from your server. Something like
- (void)viewDidLoad
{
[super viewDidLoad];
homeModel = [HomeModel new];
homeModel.delegate = self;
[homeModel downloadItems];
}
And finally you have to implement itemsDownloaded in your CarTableViewController. Do something like this:
- (void)itemsDownloaded:(NSArray *)items
{
self.carMakes = items; // Problem here
[self.tableView reloadData];
}
But the problem is HomeModel parse something different from what you have in carMakes, you have to adapt the Loop through Json objects in HomeModel.
You may wanna try AFNetworking which is a library easier to use than NSURLConnection.
I have an app that is tableview/pickerview controlled and for each table i have filled with textcellobjects.
Now when customer chooses one row and continue to next tableview I want to save that object in an NSMutableArray that is allocated/initialized in one class and I want to have that class file public so objects can be added from all the different tableview classes into the NSMutableArray.
The first 2 files MotorTVController code is working well, when a tableview cell is clicked the object is added to _myTrimArray, but I want to be able to save next tablecell object in the same _myTrimArray, i try to import the TrimArray.h(2 files last in the code here) with the same save function to MotorTVController to use the savearraycode from it, but is is not working.
So I want TrimArray.h/TrimArray.h to be able to save from all the different classes with tableviews and tableviewcell text values into one NSMutableArray.
I have been struggling with this for almost a week now, I hope someone can give me a solution, I'm kinda new at this, I know this cant be so difficult to solve, but I just don't know how?
//--------- MotorTVController.h
#import "YearPickerTVControllerPolaris.h"
#import "MotorTVController.h"
#import "motorTVCell.h"
#import "brandsTVCell.h"
#import "TrimArray.h"
#interface MotorTVController : YearPickerTVControllerPolaris
#property (nonatomic, strong) NSArray *motorLabelArray;
#property (nonatomic, strong) NSMutableArray *myTrimArray;
#end
//--------- MotorTVController.m file:
#import "MotorTVController.h"
#import "motorTVCell.h"
#import "YearPickerTVControllerPolaris.h"
#import "BackButton.h"
#import "TrimArray.h"
#interface MotorTVController ()
#end
#implementation MotorTVController
#synthesize myTrimArray = _myTrimArray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
// Getter
- (NSMutableArray *)myTrimArray
{
if (_myTrimArray == nil) {
_myTrimArray = [[NSMutableArray alloc] init];
}
return _myTrimArray;
}
- (void)viewDidLoad
{
UIImage *arrow = [UIImage imageNamed:#"backbutton"];
UIButton *arrowButton = [[UIButton alloc] initWithFrame:CGRectMake(-12, 0, 36, 36)];
[arrowButton setBackgroundImage:arrow forState:UIControlStateNormal];
[arrowButton addTarget:self action:#selector(back)
forControlEvents:UIControlEventTouchUpInside];
UIView* buttonView = [[UIView alloc] initWithFrame:CGRectMake(-12, 0, 36, 36)];
[buttonView addSubview:arrowButton];
UIBarButtonItem * backbutton = [[UIBarButtonItem alloc]
initWithCustomView:buttonView];
[self.navigationItem setLeftBarButtonItem:backbutton];
[super viewDidLoad];
_motorLabelArray = #[#"Original EH12 (4hk)",
#"Honda GX160 (5.5hk)",
#"Subaru EX17 (6hk)",
#"Honda GX200 (6.5hk)",
#"Briggs LO206 (9hk)",
#"Briggs WF206 (11HK)"];
//NSLog(#"%#", _myTrimArray);
}
-(void)back
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _motorLabelArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"motorTVCell";
motorTVCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
// Configure the cell...
[cell setTintColor:[UIColor blackColor]];
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
[cell setAccessoryType:UITableViewCellAccessoryDetailButton];
NSInteger row = [indexPath row];
cell.motorCellLabel.text = _motorLabelArray[row];
return cell;
}
// Which row is selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath
{
NSInteger rowNumber = indexPath.row;
if (rowNumber == 0)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:0]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:0]);
}
else if (rowNumber == 1)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:1]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:1]);
}
else if (rowNumber == 2)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:2]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:2]);
}
else if (rowNumber == 3)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:3]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:3]);
}
else if (rowNumber == 4)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:4]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:4]);
}
else if (rowNumber == 5)
{
[_myTrimArray addObject:[_motorLabelArray objectAtIndex:5]];
NSLog(#"You choosed %#", [_myTrimArray objectAtIndex:5]);
}
}
#end
//-------------- TrimArray.m
#import "TrimArray.h"
#import "MotorTVController.h"
#interface TrimArray ()
#end
#implementation TrimArray
#synthesize myTrimArray = _myTrimArray;
// Getter
- (NSMutableArray *)myTrimArray
{
if (_myTrimArray == nil) {
_myTrimArray = [[NSMutableArray alloc] initWithCapacity:10];
}
return _myTrimArray;
}
#end
//----------------- TrimArray.h:
#import "MotorTVController.h"
#interface TrimArray : NSMutableArray
#property (nonatomic, strong) NSMutableArray *myTrimArray;
#end
If I understood right your question , you want an arrayObject to be available globally for all the other ViewControllers right ?
If so ,your subclassing form NSMutableArray and give it Property of NSMutableArray is Wrong.
To achieve this , the simplest solution would be to use NSUserDefaults.
To sore the ArrayObject Like below.
// Get the standardUserDefaults object, store your UITableView data array against a key, synchronize the defaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:_trimArray forKey:#"TrimArray"];
[userDefaults synchronize];
To retrieve // you can retrieve the arrayObject from anywhere in your app.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSArray *arrayOfObjects = [userDefaults objectForKey:#"TrimArray"];
// Use 'yourArray' to repopulate your UITableView
I'm working on this app, but somehow, its not returning any rows in my tableviewcontroller.
here is my code:
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define kStudentenURL [NSURL URLWithString:#"http://localhost/api/api.php"]
#import "MasterViewController.h"
#import "DetailViewController.h"
#interface MasterViewController () {
NSArray *_studenten; } #end
#implementation MasterViewController
- (void)awakeFromNib {
[super awakeFromNib]; }
- (void)viewDidLoad {
[super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy) HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view]; [self.navigationController.view addSubview:HUD]; // Regiser for HUD callbacks so we can remove it from the window at the right time HUD.delegate = self; // Show the HUD while the provided method executes in a new thread [HUD showWhileExecuting:#selector(getJsonDataFromServer) onTarget:self withObject:nil animated:YES]; }
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated. }
-(void)getJsonDataFromServer {
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:
kStudentenURL];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
}); }
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
_studenten = [json objectForKey:#"studenten"];
NSLog(#"Studenten: %#", _studenten);
NSLog(#"%u", _studenten.count); }
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1; }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _studenten.count; }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDictionary *student = [_studenten objectAtIndex:0];
NSString *studentNaam = [student objectForKey:#"studentNaam"];
NSString *studentAchterNaam = [student objectForKey:#"studentAchterNaam"];
cell.textLabel.text = studentAchterNaam;
cell.detailTextLabel.text = studentNaam;
return cell; }
/* // Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { }
*/
/* // Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES; }
*/
/*- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDate *object = _objects[indexPath.row];
[[segue destinationViewController] setDetailItem:object];
} }*/
#end
I know my json is comming in correctly. the NSLogs are returning the data i ask, but i cant seem to get any rows. Can someone give me a hand? tnx
Simple answer -- you need to call [(your tableview) reloadData] once you've finished loading that data array!
Presumably you've got your tableview on the storyboard right now, and you've set it's datasource and delegate to your view controller. You will also need to have a property in your view controller to that tableview. You might have some code that looks like this.
#interface MasterViewController () {
NSArray *_studenten;
}
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#end
#implementation MasterViewController
- (void)fetchedData:(NSData *)responseData {
NSError* error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
_studenten = [json objectForKey:#"studenten"];
NSLog(#"Studenten: %#", _studenten);
NSLog(#"%u", _studenten.count);
[self.tableView reloadData];
}
#end
My guess is that you are never getting a valid cell returned from dequeueReusableCell. What I recommend doing is after you try to reuse a cell, check to see if it is nil, if so you need to alloc a new cell. I've added the code to your function.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
if(!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
NSDictionary *student = [_studenten objectAtIndex:0];
NSString *studentNaam = [student objectForKey:#"studentNaam"];
NSString *studentAchterNaam = [student objectForKey:#"studentAchterNaam"];
cell.textLabel.text = studentAchterNaam;
cell.detailTextLabel.text = studentNaam;
return cell; }
Trying to make an my RSS Feed app have the summary inside the label, I have parsed the description (summary), but I don't understand how to add it in the UITableViewCell. I am currently using UITableViewCellStyleSubtitle, so I can show the title of each post and the date below it. How do I add one more below it to show summary of each post?
MasterViewController.h (TableView Header)
#import <UIKit/UIKit.h>
#class RSSChannel;
#class WebViewController;
#interface MasterViewController : UITableViewController
<NSXMLParserDelegate>
{
NSURLConnection *connection;
NSMutableData *xmlData;
RSSChannel *channel;
}
- (void)fetchEntries;
#property (nonatomic, strong) WebViewController *webViewController;
#end
MasterViewController.m (TableView Implementation)
#import "MasterViewController.h"
#import "RSSChannel.h"
#import "RSSItem.h"
#import "WebViewController.h"
#interface MasterViewController () {
NSMutableArray *_objects;
}
#end
#implementation MasterViewController
#synthesize webViewController;
- (void)awakeFromNib
{
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self fetchEntries];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (void)insertNewObject:(id)sender
{
if (!_objects) {
_objects = [[NSMutableArray alloc] init];
}
[_objects insertObject:[NSDate date] atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
#pragma mark - Table View
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"The amount of items in the table: %u", [[channel items] count]);
return [[channel items] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"UITableViewCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:#"UITableViewCell"];
}
RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
[[cell textLabel] setText:[item title]];
[[cell detailTextLabel] setText:[item date]];
return cell;
}
- (void)fetchEntries
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc] init];
// Construct a URL that will ask the service for what you want -
// Note we can concatenate literal strings together on multiple lines in this way it
// results in a single NSString instance
NSURL *url = [NSURL URLWithString:
#"http://sephardijews.com/feed/"];
// Putting the URL we made into an NSURLRequest, so we can connect to the url data that we specifed
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Creating a connecting that will exchange this request for the data from the URL we specifed
connection = [[NSURLConnection alloc] initWithRequest:req
delegate:self
startImmediately:YES];
}
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifedName
attributes:(NSDictionary *)attributeDict
{
NSLog(#"%# found a %# element", self, elementName);
if ([elementName isEqual:#"channel"]) {
// If the parser saw a channel, create new instance, store in our ivar
channel = [[RSSChannel alloc] init];
// Give the channel object a pointer back to ourselves for later
[channel setParentParserDelegate:self];
// Set the parser's delegate to the channel object
[parser setDelegate:channel];
}
}
// Method used to start at the beginning of the instance of the tableview, it will intialize the connection method to retrieve the posts from the URL
/* - (id) initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
[self fetchEntries];
}
return self;
}
*/
// This method will be called several times as the data arrives
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[xmlData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
// Create the parser object with the data received from the web service
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
// Give it a delegate - don't worry about the warning
[parser setDelegate:self];
// Tell it to start parsing - the documet will be parsed and the delegate of NSXMLParser will get all of its delegate messages sent to it before this line finishes execution - it is blocking
[parser parse];
// Get rid of the XML data as we no longer need it
xmlData = nil;
// Get rid of the connection, no longer need it
connection = nil;
// Reload the table
[[self tableView] reloadData];
NSLog(#"%#\n %#\n %#\n", channel, [channel title], [channel infoString]);
}
- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
// Release the connection object, we are done with it cause' there is no connection
// Setting the connection to nil will stop the connection because it is nothing/0
connection = nil;
// Release the xmlData object. We stopped to connection to put the data in the xmlData object, so we set it to nil also
xmlData = nil;
// Grab the description of the error object passed to us, so we can tell the user
NSString *errorString = [NSString stringWithFormat:#"Fetch failed: %#", [error localizedDescription]];
// Create and show an alert view to the user with the error string to tell them the error in the process of the connection
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error"
message:errorString
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[av show];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Push the web view controller onto the navigation stack - this implicitly
// creates the web view controller's view the first time through
[[self navigationController] pushViewController:webViewController animated:YES];
//Grab the selected item
RSSItem *entry = [[channel items] objectAtIndex:[indexPath row]];
//Constructs a URL with the link string of the item
NSURL *url = [NSURL URLWithString:[entry link]];
// Construct a request object with that URL
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Load the request into the web view
[[webViewController webView] loadRequest:req];
// Set the title of the web view controller's navifation item
[[webViewController navigationItem] setTitle:[entry title]];
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#end
Try changing the UITableViewCellStyle to custom and dragging in your own UITextLabel objects to the prototype cell. Make #propertys for each of your data items in your TableViewController...
#interface MasterViewController ()
NSMutableArray *_objects;
#property (nonatomic, strong) IBOutlet UILabel *title;
#property (nonatomic, strong) IBOutlet UILabel *date;
#property (nonatomic, strong) IBOutlet UILabel *summary;
#end
Then connect the UITextLabels to their respective data.
I'm using this tutorial to practice creating an extremely basic twitter app: http://www.codeproject.com/Articles/312325/Making-a-simple-Twitter-app-using-iOS-5-Xcode-4-2#setting-up-the-table-view
The only difference in my app is I'm only using tableView ViewController. I can't seem to get this to work.
ViewController.h
#interface ViewController : UIViewController {
NSArray *tweets;
}
-(void)fetchTweets;
#property (retain, nonatomic) IBOutlet UITableView *tableView;
#end
ViewController.m
#import "ViewController.h"
#import "Twitter/Twitter.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize tableView = _tableView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self fetchTweets];
}
- (void)fetchTweets
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: #"https://api.twitter.com/1/statuses/public_timeline.json"]];
NSError* error;
tweets = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *text = [tweet objectForKey:#"text"];
NSString *name = [[tweet objectForKey:#"user"] objectForKey:#"name"];
cell.textLabel.text = text;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", name];
return cell;
}
- (void)viewDidUnload
{
_tableView = nil;
[self setTableView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
you forgot to define delegate & datasource for your table, and didn't implement the protocols right as far as i see in your code,
try in your .h file:
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
// your implementation...
}
and in your .m file in viewDidLoad
self.tableView.dataSource = self;
self.tableView.delegate = self;
the numberOfRows, cellForRow, etc... methods wont work until you define your delegate & datasource for this table :)