I was wondering what is the best way to go about adding a new cell to a tableview in iOS. Let's say I have a firstviewcontroller and a secondviewcontroller. On the firstviewcontroller I have a tableview already populated with some data, I also have a navigation bar with an add button on the top. Tapping the add button will present a new view and then I want to pass data from that secondviewcontroller to firstviewcontroller and populate my tableview with it.
Thanks,
Sam
You secondViewController should create a delegate protocol. Your firstViewController should then be assigned as its delegate.
Once secondViewController saves the data it calls a method that your firstViewController should implement
A good exemple here:
How do I create delegates in Objective-C?
To get you started: secondViewController.h
#protocol secondViewControllerDelegate;
#interface secondViewController : UIViewController{
id<secondViewControllerDelegate> __unsafe_unretained delegate;
}
#property (nonatomic, unsafe_unretained) id<secondViewControllerDelegate> delegate;
#end
#protocol secondViewControllerDelegate <NSObject>
- (void)dataSaved;
#end
You can add a new class with tableView data source. initiate it with nesessary data (from both View controllers. use delegate to cooperate them) and after anu data chaging call [tableView setDataSource:]:
// DataSourceAtoZ.h
#import <Foundation/Foundation.h>
#import "MallsViewController.h"
#interface DataSourceCategory : NSObject <UITableViewDataSource> {
NSMutableArray *data;
UITableView *tableView;
}
#property (nonatomic, retain) NSMutableArray *data;
- (id)initWithData:(NSMutableArray *)d;
#end
then, anywhere in your code, compose data you wish to be in tableView and set dataSource:
NSMutableArray *dt = [[NSMutableArray alloc] init];
for (int i = 0; i < [categories count]; i++) {
NSMutableArray *names = [[NSMutableArray alloc] init];
[names addObject:[[categories objectAtIndex:i] objectAtIndex:0]];
for (int j = 1; j < [[categories objectAtIndex:i] count]; j++) {
NSRange match = [[[categories objectAtIndex:i] objectAtIndex:j] rangeOfString:[params objectAtIndex:0]];
if (match.length != 0) {
[names addObject:[[categories objectAtIndex:i] objectAtIndex:j]];
}
}
[dt addObject:names];
[names release];
}
dsCategory = [[DataSourceCategory alloc] init];
dsCategory = [dsCategory initWithData:dt];
[dt release];
You should create your arrays in the App delegate and then call them and change them however you want from there..
MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate];
once you have this line you can connect between two classes and call any methods on the delegate for example:
[appDelegate populateMyArray];
you don't add "new cells" like you described it, you use the same cells and populate them with different data.
Related
I've stuck in the problem.
I have a storyboard with several view controllers.
What I need to do is:
I need to pass an array from FirstViewController to SecondViewController (they are not neighbors and are not connected via segue) where PikerView will upload the array. After that the picked result should be passed to ThirdViewController.
I have tabbed applicateion where FirstViewController and SecondViewControllers are connected to Tab Bar View Controller and ThirdViewController is connected with SecondViewController via Push Segue.
See how I try to pass data form First to Second
CategoryExpencesViewController.h
#import <UIKit/UIKit.h>
#import "AddCategoryViewController.h"
#import "CategoryPickerViewController.h"
#interface CategoryExpencesViewController : UITableViewController <AddCategoryViewControllerDelegate>
#property(nonatomic, weak) IBOutlet UIBarButtonItem *editButton;
#property(nonatomic, strong) NSMutableArray *categories; //list of category items
#property(nonatomic, strong) NSMutableArray *listOfCategories; //list of category names
CategoryExpencesViewController.m
-(void)updateArray
{
CategoryPickerViewController *controller = [[CategoryPickerViewController alloc]init];
controller.categoryList = [[NSMutableArray alloc]init];
controller.categoryList = listOfCategories;
NSLog(#"%d", [listOfCategories count]);
NSLog(#"%d", [controller.categoryList count]);
}
I think you need this
Use your's Push Segue.
segue.sourceViewController (or self) will point at SecondViewController.
segue.sourceViewController.tabBarController will point at Tab Bar Controller.
From Tab Bar Controller you will find your's FirstViewController.
I suppose you would have solved it, but i post this just for the record:
Wrap the array into a class, and make it have a static construction method:
Wrapper.h:
#property (nonatomic, strong) NSMutableArray* array;
+(Wrapper*)createArray;
Wrapper.m:
+(Wrapper*)createArray{
static Wrapper* instance = nil;
if (instance == nil) {
instance = [[Wrapper alloc] init];
//Your initialization code for the array
}
return instance;
}
Then, in your FirstViewController:
-(void)updateArray{
CategoryPickerViewController *controller = [[CategoryPickerViewController alloc]init];
controller.categoryList = [[NSMutableArray alloc]init];
controller.categoryList = [[Wrapper createArray] array];
NSLog(#"%d", [listOfCategories count]);
NSLog(#"%d", [controller.categoryList count]);
}
As this is the first call to Wrapper, the array is generated.
Then in your SecondViewController, when you call:
secondView.categoryList = [[Wrapper createArray] array];
and you obtain the same array as in FirstViewcontroller.
have you thought of NSUserDefault try it and you can also create a instance global variable in AppDelegate class and access it by creating an instance of AppDelegate in any other ViewController but i think NSUserDefault is the best option from all.
I have a question...
I have couple(2) of ViewCotroller.
name are ViewController and DetailViewController
DetailViewController has data(Relationship in Coredata).
this is DetailViewController code.
NSSet *tags = self.bookInfo.details.tags;
tagNamesArray = [[NSMutableArray alloc] initWithCapacity:tags.count];
for (Voca_Tag *tag in tags) {
[tagNamesArray addObject:tag.mean];
}
I want using that tagNamesArray.count in ViewController.
also, I was used
DetailViewController *detailViewController = [[DetailViewController alloc]init];
[detailViewController.tageNamesArray count];
it didn't work.
I want use the Count to cell.text on UITableView.
pastebin.com/RwuR6PDt << ViewController
pastebin.com/2F345vg7 << DetaulViewController
plz Check...
You should write your delegate: In SecondViewController.H:
#protocol messageDelegate <NSObject>
#optional
-(void) sendDataCount:(NSInteger) i;
#end
#interface SecondViewController : NSString
#property (nonatomic, assign) id <messageDelegate> delegate;
#end
In SecondViewController.m:
-(void)readyToSend
{
[self.delegate sendDataCount:__YOURCOUNT__];
}
In ViewController.h:
#interface ViewController : UIViewController<messageDelegate>
#end
In ViewController.m: in
- (void)viewDidLoad {
SecondViewController *secondViewController = [[SecondViewController alloc] init];
secondViewController.delegate = self;
}
-(void) sendDataCount:(NSInteger) i
{
NSLog(#"Your Count = %d",i);
//send Data using POST method
}
Hope it will help!
This is because tafNamesArray does not have memory allocation at that time and hence this array will returns nil and its count will be zero .
If you want to get [tafNamesArray count ] ,first call that method which initilize tafNamesArray, for example :
In DetailViewController
-(void)array
{
NSSet *tags = self.bookInfo.details.tags;
tagNamesArray = [[NSMutableArray alloc] initWithCapacity:tags.count];
for (Voca_Tag *tag in tags) {
[tagNamesArray addObject:tag.mean];
}
}
then In ViewController
call :
DetailViewController *detailViewController = [[DetailViewController alloc]init];
//First call this method
[detailViewController array];
//then this line will work
int i = [detailViewController.tafNamesArray count];
I have two arrays (first names, Last names) in my TableView (cell.textLabel and cell.detailTextLabel)
I want to make a search bar in this TableView.
I have created class with two string.
#interface clientContent : NSObject { }
#property (nonatomic, strong) NSString *clName;
#property (nonatomic, strong) NSString *clLast;
#end
then I have created array in main class (which have Table view) and added my information
like this
for (int i = 0; i < PQntuples(clientQuery); i++)
{
clientContent *cc = [[clientContent alloc] init];
cc.clName = [[NSString alloc] initWithUTF8String:PQgetvalue(clientQuery, i, 0)];
cc.clLast = [[NSString alloc] initWithUTF8String:PQgetvalue(clientQuery, i, 1)];
[allClients addObject:cc];
}
after this I load it into tableView;
clientContent *cc = [allClients objectAtIndex:indexPath.row];
cell.textLabel.text = cc.clName;
cell.detailTextLabel.text = cc.clLast;
}
Then I use
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
How to make it right? I can't understand..
You should override searchDisplayController:shouldReloadTableForSearchString: delegate method of UISearchDisplayController and filter datasource array for searchResultsTableView as you want.
You can apply predicate on your array(array of clientContent object) and change dataSource array. Using predicate you can filter your array on both fields(clName & clLast).
You can get help related to predicates from https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/Reference/NSPredicate.html
I have just solved another problem regarding the same piece of code but I want to separate my 2 problems.
I want to store in my AppDelegate the table generated by an Rss parser so that it is not necesary to do it again each time the viewcontroller that displays the list is loaded, To do so, I have the following code:
AppDelegate.h
#import <Three20/Three20.h>
#import "NewsRssParser.h"
#import "NewsRss.h"
#class NewsRssParser;
#class NewsRss;
#interface AppDelegate : NSObject <UIApplicationDelegate,NewsRssParserDelegate> {
NewsRssParser * _rssParser;
NSMutableArray * _newsRssArray;
}
#property(readwrite, retain) NewsRssParser * rssParser;
#property(readwrite, retain) NSMutableArray * newsRssArray;
#end
ApDelegate.m
[...]
#implementation AppDelegate
#synthesize rssParser = _rssParser;
#synthesize newsRssArray = _newsRssArray;
[...]
At a certain stage of execution of the app, the table is properly populated by the Rss parser. When this happens, I want to transform it into a format that can be displayed in another view controller:
(void)myFunction{
NSMutableArray *dsItems = [[[NSMutableArray alloc] init] autorelease];
for(NewsRss *rssItem in self.rssParser.rssItems)
{
NSString * rssItemTitle = [rssItem title];
NSString * rssItemAuthor = [#"par " stringByAppendingString:[rssItem author]];
NSString * rssItemDescription = [rssItem description];
NSString * rssItemLinkUrl = [rssItem linkUrl];
NSString * rssItemImageUrl = [rssItem mediaUrl];
TTTableMessageItem *tMsgItem = [TTTableMessageItem itemWithTitle:rssItemTitle caption:rssItemAuthor text:rssItemDescription timestamp:nil imageURL:rssItemImageUrl URL:rssItemLinkUrl];
[self.newsRssArray addObject:tMsgItem];
[dsItems addObject:tMsgItem];
}
}
I controlled that this works by showing the [_newsRssArray count] in gdb with NSLog. It returns 10 which is the number of articles I have in my RSS feed.
This is when I want to load my ViewController to show the list of articles. I do it this way:
NewsVc.h
#import <Three20/Three20.h>
#protocol NewsVcDelegate;
#class AppDelegate;
#interface NewsVc : TTTableViewController {
id<NewsVcDelegate> _delegate;
AppDelegate * _appDelegate;
}
#property(nonatomic,assign) id<NewsVcDelegate> delegate;
#property(nonatomic, retain) AppDelegate * appDelegate;
#end
#protocol NewsVcDelegate <NSObject>
- (void)NewsVc:(NewsVc*)controller didSelectObject:(id)object;
#end
NewsVc.m
[...]
- (void)loadNewsFromParser {
self.tableView.allowsSelection = NO;
//reload the table view
TTListDataSource *ds = [[TTListDataSource alloc] autorelease];
//NSMutableArray *dsItems = [[[NSMutableArray alloc] init] autorelease];
NSLog(#"NewsVC(loadNewsFromParser):count/newsRssArray=%d", [self.appDelegate.newsRssArray count]);
NSLog(#"NewsVC(loadNewsFromParser):count/rssItems=%d", [self.appDelegate.rssParser.rssItems count]);
[ds initWithItems:self.appDelegate.newsRssArray];
self.dataSource = ds;
self.tableView.allowsSelection = YES;
}
[...]
But in this function of the ViewController, I see the array empty, as well as when I try to access directly the parsed data of the NewsRss. What it wrong on my code of AppDelegate/NewsVc to be able to access this array from NewsVc?
Thanks for your help ! I feel very slow today stuck on this...
Where do you assign appDelegate? There must be a line like this somewhere in your view controller initialization:
self.appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
Im trying to get a UITableView to display items contained within an array.
This array is contained within a class (HX_ParkingSearch).
I have a ref to this class that contains the array inside the app delegate class, to enable the views to access it.
Problem is that I get one page of results displaying correctly inside the tableview
but when i try and scroll down an exception occurs when trying to access the next item in the array.
It turns out that when i scroll down and the cellForRowAtIndexPath method fires,
the items inside the array are invalid and appear to have been released but i dont understand where
they are being released!
Does anyone have any ideas because this is really doing my head in now!
Many thanks,
Chris.
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
HX_ParkingLocation *location;
bookingApp2AppDelegate *del = (bookingApp2AppDelegate *) [[UIApplication sharedApplication] delegate];
NSMutableArray* array = [del.parkingSearch locations];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
location = (HX_ParkingLocation*) [array objectAtIndex: [indexPath row] ];
return cell;
}
#import <Foundation/Foundation.h>
#interface HX_ParkingLocation : NSObject
{
NSString *name;
}
#property(retain,nonatomic) NSString* name;
/*
Initialises this Location instance by passing in the name and code of the location and the URL of the webapi product endpoint.
The URL is used to find available products at this location.
*/
-(id) initWithName: (NSString*) n;
#end
#import <Foundation/Foundation.h>
#interface HX_ParkingSearch : NSObject
{
NSMutableArray* locations;
}
#property (retain) NSMutableArray* locations;
-(BOOL) loadLocations;
#end
#import "HX_ParkingSearch.h"
#import "HX_Parking_Location.h"
#implementation HX_ParkingSearch
#synthesize locations;
//Finds the locations
-(BOOL) loadLocations
{
[locations release];
//Create array to hold locations
locations = [[NSMutableArray alloc] initWithCapacity:30];
//Loop through all returned locations
for(int i=0;i<15;i++)
{
//Get location name
NSString* n = [NSString stringWithFormat:#"Item #%i",i ];
//Create location instance, which retrieves availability and product information and stores the information in location object.
HX_ParkingLocation* location = [[HX_ParkingLocation alloc] initWithName:n];
//add to array
[locations addObject:location];
}
return YES;
}
#end
#import <UIKit/UIKit.h>
#import "HX_ParkingSearch.h"
#interface bookingApp2AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
HX_ParkingSearch *parkingSearch;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#property (retain) HX_ParkingSearch *parkingSearch;
#end
#implementation bookingApp2AppDelegate
#synthesize window;
#synthesize navigationController;
#synthesize parkingSearch;
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
//Create new parking search instance by specifying the endpoint urls
HX_ParkingSearch* search = [[HX_ParkingSearch alloc] init];
[search loadLocations];
parkingSearch = search;
//NSLog(#"Search Retain count = %i" ,[search retainCount]);
[window addSubview:[navigationController view]];
//[window addSubview:[navigationController initWithNibName:#"VC_Locations" bundle:[NSBundle mainBundle]]];
[window makeKeyAndVisible];
}
Is there a reason that you're init-ing your array with a capacity of 30 in loadLocations, but only inserting 15 items?
what's in this method for your datasource?:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
and also:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
the tableview may just be trying to grab an index that's out of bounds of locations