I'm developing an application, and I decided to use three20 + TTTableViewControllers for settings-like page.
So I have my ViewController:
#interface MyViewController : TTTableViewController
That initalizes my datasource:
-(void) createModel {
self.dataSource = [[[MyDataSource alloc] init] autorelease];
}
My datasource then initalizes different kind of controls (some three20 standard, some custom classes), for example
UISwitch* switchy = [[[UISwitch alloc] init] autorelease];
TTTableControlItem* switchItem = [TTTableControlItem itemWithCaption:#"UISwitch" control:switchy];
self.dataSource = [TTListDataSource dataSourceWithObjects:switchItem,...,...,nil]
Now there are a few things that are not clear to me..
1- How can I access data from the viewcontroller? (ie: Read the value of the switch).. Right now i use something like
bool ron = ((SwitchTableItemCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]]).switchField.isOn;
that onestly looks terrible.
2- How can I set the viewcontroller as a delegate for the items (ie: I want have MyViewController as a delegate for all the text fields)
3- What's the best way to add/remove a field. Right now I just reassign the datasource from scratch but again, looks a bit ugly
Thanks!
1- How can I access data from the viewcontroller? (ie: Read the value of the switch).. Right now i use something like
You should access the data source directly:
self.dataSource.items
this is an NSMutableArray.
2- How can I set the viewcontroller as a delegate for the items (ie: I want have MyViewController as a delegate for all the text fields)
It depends on what you want to do. The only item I see in your code is a UISwitch, which has no delegate; but if the item had one, I would do:
MYItem* switchy = [[[UISwitch alloc] init] autorelease];
switchy.delegate = self;
3- What's the best way to add/remove a field. Right now I just reassign the datasource from scratch but again, looks a bit ugly
Since self.dataSource.items is an NSMutableArray, you can remove items from it thorugh removeObjectAtIndex: and add through addObject:.
For basic setup of TTableviewcontroller of three 20,
use this link http://www.raywenderlich.com/656/introduction-to-three20
Related
I am trying to pass a string back and forth between the view Controllers, so for example as soon as I click on a tab bar button (+) in the first View, second view opens (PresentModalViewController) and it has a Text Field. So anything I type, I take it into a string(this string is an object of the first view) and I am trying to append that string to a tableview loaded in the first View.
Note: My string object is declared like this
View1.h
NSString *string
#property (copy) NSString *string;
View1.m
#synthesize string;
And in the View 2 I am passing the textField Value like this
View2.m
View1 *view1 = [[View1 alloc] initWithNibName:#"View1" bundle:nil];
view1.string = [[NSString alloc] initWithFormat:#"%#", TextField.text];
Problem - When I NSLog this value inside the View2, it grabs the value from the Text Field but in order for me to load the previous view, I need to dismiss this View2. So as soon as this View2 is dismissed when I try to access the same string object in my view 1. It says the string object is null.
Question - Could someone tell me
1. How to get the text Field value from view 2 to view 1 after dismissing View 2 (does it really makes all its objects null when dismissed?)
2. How to append that string to the last index of a NSMutableArray?
This is a very good question that I also had trouble figuring out when I started coding for the iOS. Basically, you don't need to initialize a new view1 because the tabbar controller already holds the view1 object in its viewControllers property. Also, alloc/init'ing the string in not necessary in this situation.
Therefore, you would want to change this:
View1 *view1 = [[View1 alloc] initWithNibName:#"View1" bundle:nil];
view1.string = [[NSString alloc] initWithFormat:#"%#", TextField.text];
To something like this:
View1 *view1 = [self.tabbarController.viewControllers objectAtIndex:0];
view1.string = textField.text;
Or even:
((View1 *)[self.tabbarController.viewControllers objectAtIndex:0]).string = textField.text;
Part 2:
How to append that string to the last index of a NSMutableArray?
NSMutableArray *someArray = [[NSMutableArray alloc] init];
[someArray addObject:string];
[someArray addObject:#"anotherString"];
The answer from #chown will definitely work if the ViewController you're sending the string to is the base controller of a tabBarController.
If you were several levels deep into a NavigationController stack, then you'll need a different approach.
The approach I'd recommend would be to create a protocol. This is where you create a delegate of view2 to pass the string back down the stack before the view is dismissed.
There are loads of examples of this code both in the Apple Documentation and on the Internet (StackOverflow included) but here's a quick run down...
In View2.h
#import <UIKit/UIKit.h>
//define the protocol, so you can set the delegate to this type
#protocol View2Delegate;
#interface View2 : UIViewController
//other properties etc
#property (assign) id <View2Delegate> delegate;
#end
//put the actual protocol definition here so we can pass a reference to ourself back up too if needed...
#protocol View2Delegate
- (void)view2:(View2*)view passingStringBack:(NSString *)stringToPassBack;
#end
In View2.m you can call that delegate method where ever you like but here's an example:
- (void)viewWillDisappear:(BOOL)animated
{
if(self.delegate)
[self.delegate view2:self passingStringBack:#"String I'm passing back"];
[super viewWillDisappear:animated];
}
Then in View1.h
#interface View2 : UIViewController <View2Delegate>
and View1.m
- (void)view2:(View2*)view passingStringBack:(NSString *)stringToPassBack
{
NSLog(#"%#", stringToPassBack);
}
Another option would be to post a notification, but that is more a broadcast scenario than a targeted message so I won't bother posting example code for that.
Im fairly new to Objective-C. I am in the process of passing an array from an NSObject to a view controller (not my root). The NS object file, finishes with the array poolArray.
Ive also used self.poolArray = nil; in void(dealloc). When passing this to my view controller, what are the steps I have to take?
Edit: To be more specific to my cause, what if I was just to deal with two view controllers?
-(void)createData {
//poolFixtures being the text within each cell of my table view.
NSMutableArray *poolFixtures;
groupSections=[[NSMutableArray alloc] initWithObjects: #"Pool Stages", nil]
poolFixtures=[[NSMutableArray alloc] init];
[poolFixtures addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"This is a name",#"name",nil]];
fixtureData=[[NSMutableArray alloc] initWithObjects: poolFixtures, nil];
[poolFixtures release];
}
I have a similar set up for my second view controller. However, the titles needed for the second one require me to download data from a html file, parse them into the format i want etc. When used in the second view controller it takes a long time (I presume because of the html loading time). What I am trying to accomplish (what I thought i could do with an NSobject), is starting the data collection as soon as the user opens the app; so, by the time the user gets to the second view controller, it is loaded and ready.
Therefore I am wondering if I could do the downloading, and parsing in the root view controller, and send the array across to the second view controller for use when needed. I thought I would be able to use the createData part of my root implementation to do so.
For this, my suggestion is implement delegate methods. I guess u know about protocols in objective C. More info about delegate pattern.
Steps to do.
1. After ur app is launched, the view controller set the delegate and start downloading in background thread.
2. After the download is finished, the downloaded data will be set through the delegate methods.
Hope u will get my point. Any doubt, post it here.
I may be misunderstanding you, but this is what you typically do....
Object obj = [[Object alloc] init];
ViewController *vc = [[ViewController alloc] initWithNibName:#"NibName" bundle:nil];
// this is a public property of the viewcontroller
vc.array = [object methodThatReturnsArray];
[self.navigationController pushViewController:vc];
This is what the methodThatReturnsArray would look like
-(NSArray *)methodThatReturnsArray
{
NSArray* array = [[[NSArray alloc] init] autorelease];
// some code here that adds to the usefulness of the array
return array;
}
how to reload in UITableView class.
I am using the reloadData method but it's not working.
- (id)initWithCoder:(NSCoder *)coder
{
if (self = [super initWithCoder:coder])
{
[self init];
}
return self;
}
-(id)init
{
appdelegate=[[UIApplication sharedApplication]delegate];
[appdelegate readLiteratureFromDatabase];
tbl_obj.backgroundColor=[UIColor clearColor];
tbl_obj.delegate = self;
tbl_obj.dataSource = self;
[tbl_obj reloadData];
array_content = [[NSMutableArray alloc] init];
return self;
}
Here the init method call in another class. So at that time table are not reload.
please help!
From looking at your code it appears that you really need to read this;
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html
You should not have a method called init that does not call up to super, that will eventually hose things.
Setting your docs ivar to an empty immutable string does nothing but waste memory. Eventually you will need to set docs to something real, wait till that point to do any allocation.
Next download the TableViewSuite sample from here;
http://developer.apple.com/library/ios/#samplecode/TableViewSuite/Introduction/Intro.html%23//apple_ref/doc/uid/DTS40007318
And take a look at the simple sample.
Please take the time to study that sample, it will help you understand table views.
May be that you might not have attached DataSource and Delegate to your XIB
or
You can do it through code using:
self.tableView.delegate = self;
self.tableView.datasource = self;
Also you have to add it as below:
#interface <YourViewControllerName>:UIViewController <UITableViewDelegate,UITableViewDataSource>
EDIT:
But you should try and understand that your controls like UITableView cannot be directly called and set into your UIView class.
It should be UIViewController only then it is possible to add and fillup the data into the TableView.
So your option is to call the data delegate and datasource methods and also the reloadData on the ViewController which works as parentView for the this UIView.
So unless you do this way, I fear that it is not possible.
Hope this helps you.
UIView does not have a reloadData method. UIView Class Reference
Maybe you can show your code so we can see what you are trying to do?
I had the same prob and i just used the viewDidLoad to add the data and in the end i used [super loadView]; and it reload.
im my app that im tring to build, i want to have a table view, where you select a row e.g email address. the view pushes to a simple page with a uitextField, when you hit the save button it pops the view controller back to the initial page, where the user can select the next field.
the issue that i am having is passing the information entered in the textfile back to the first view controller. this should be really simple, but anything i try just does not work
what is the best way to go around this.
thanks
You are probably thinking about the problem backwards. In an MVC system like Cocoa, the job of View Controllers is to manage views, not data. Create a model object to hold the data you're updating. When you create a view controller, pass the model object to it. It may update the model with changes the user makes. It should not worry about who called it, or who it returns to. It should just update the model object, and other interested parties should read the model object. As an example:
SettingsViewController would have a model object called Settings
When you dive into a detail view controller like EmailViewController, you pass the settings to it like emailViewController.settings = self.settings before presenting it.
When the user makes changes, just update the object like self.settings.emailAddress = ...
This separates your view logic from your model logic, which is a key features of Cocoa patterns. If you fight this pattern, you're going to often find yourself thinking "it sure is hard to get there from here."
You can either use a delegate method or, even simpler, just define an instance variable NSString *textEntry in the first view controller that can be set (property/synthesize) and then access that view controller from the stack.
For example, in the pushed view, do something like:
FirstViewController *firstViewController = [[[self navigationController] viewControllers] objectAtIndex:0];
[firstViewController setTextEntry:[textfield text]];
The easiest way I found to do this is using NSNotificationCenter.
In the ViewController with the TableView:
- (void)updateRowValue:(NSNotification *)notification{
NSDictionary *valuesDictionary = [[NSDictionary alloc] initWithDictionary: [notification userInfo] copyItems:NO];
NSString *newString = [valuesDictionary objectForKey:#"StringVal"]
}
This is the method called when row is selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TextFieldViewController *tfvc = [[TextFieldViewController alloc] init];
[tfvc setPostNotificationString:#"updateRowValue"];
[self.navigationController pushViewController:tfvc animated:YES];
}
Now in the viewController with the textField, when you press the button to return to the previous viewController call this:
- (IBAction)saveButtonPressed{
NSArray *valuesArray = [[NSArray alloc] initWithObjects:textField.text,nil];
NSArray *keyArray = [[NSArray alloc] initWithObjects:#"StringVal",nil];
NSDictionary *dictionary = [[[NSDictionary alloc] initWithObjects:valuesArray forKeys:keyArray] autorelease];
[[NSNotificationCenter defaultCenter] postNotificationName:[self postNotificationString] object:self userInfo:dictionary];
[[self navigationController] popViewControllerAnimated:YES];
}
I have a tab bar application with 4 different tabs.(4 different views)
When my app first launches, the first thing I need to do is bring in my data which is located in a plist. This isn't a problem. My problem is, the data is displayed in each tab in a different way.
Where do you suggest the best place to load the data is?
Currently I'm using viewDidLoad of the first viewController. But from here, what do you think the best way to make the data available to the other views is? Perhaps make the other 3 views become a delegate for the 1st view?
Any suggestions would be much appreciated
Thanks for you help.
Mike.
I don't know why each of the four views can't have a reference to the dictionary, and your application delegate loads from the plist and set the references. Is your data very large?
The little data I've had that is truly global in this way I've made a property on my AppDelegate class. Your view controllers can all access it with
MyAppDelegate* delegate = [UIApplication sharedApplication].delegate;
id thing = [delegate.myDictionary objectForKey:#"someKey"];
This is an often asked question here. You should look at the MVC design pattern. Your dictionary would be a model in this scenario and all the controllers/views that need to access it should have their own property for it. The loading can be done in another controller/view with a progress bar, in the application delegate or in the first tab; that depends on your situation.
The classes would look a bit like this:
#interface Model : NSObject {…}
- (void) load;
#end
#interface ControllerA : UIViewController {…}
#property(retain) Model *model;
#end
#interface ControllerB : UIViewController {…}
#property(retain) Model *model;
#end
#implementation ApplicationDelegate
- (void) applicationDidFinishLaunchingAndWhateverElseIsUsuallyHere
{
Model *model = [[Model alloc] init];
[model load];
ControllerA *controllerA = [[ControllerA alloc] init…];
[controllerA setModel:model];
ControllerB *controllerB = [[ControllerB alloc] init…];
[controllerB setModel:model];
[model release];
// The syntax here is probably off, you should get the idea
UITabBarController *tabs = …;
[tabs setViewControllers:controllerA, controllerB, nil];
[window addSubview:tabs.view];
[window makeKeyAndVisible];
}
I don't have any experience with Tab Bar views, but it looks like you want to create a singleton class, so that you can access your dictionary globally.