Passing an array from NSObject to a View Controller - iphone

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;
}

Related

How to update an object from a previous ViewController?

I have a view controller called searchUpdateController, it has a button to push a new view controller called editController. In the editController there is a button called Save and it contains the following code:
searchUpdateController = [[SearchUpdate alloc] init];
[self.navigationController popViewControllerAnimated:YES];
[searchUpdateController.fieldsValArray replaceObjectAtIndex:3 withObject:joinedString];
[searchUpdateController.mainTable reloadData];
[searchUpdateController release];
fieldsValArray is a NSMutableArray property in searchUpdateController and mainTable is the tableView in the searchUpdateController. I wanted to update the content of the fieldsValArray and reload the data of the tableView. Nothing happens when I click the Save button. Any ideas what I'm missing here?
Here you are creating a new objet not using the old one in the code
searchUpdateController = [[SearchUpdate alloc] init]; set them searchUpdateController from SearchUpdateController class. so that it point to that object that pushes the editController
Dont do this -> searchUpdateController = [[SearchUpdate alloc] init];
Here you are creating new object, which is not referring to your older object
Before moving back to searchUpdateController do this:
Get second last object from self.navigationController. viewControllers, which is nothing but the searchUpdateController
Now you are having the same object so update the array data whichever you want
Now there are two possibilities to reload data:
Use NSNotification and fire a notification to parent view controller where need to reload table
Call a method of parent class which will reload table
Hope this is what you want.

NSEntityDescription insertNewObjectForEntityForName returns NSManagedObject just deleted

- (void)addPlace {
//set up add controller
PlacesAddViewController *addController = [[PlacesAddViewController alloc] initWithStyle:UITableViewStyleGrouped];
addController.delegate = self;
// create new place and assign it to add controller
Place *newPlace = [NSEntityDescription insertNewObjectForEntityForName:#"Place" inManagedObjectContext:self.managedObjectContext];
addController.place = newPlace;
// set up navigation controller
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addController];
[self presentModalViewController:navigationController animated:YES];
// release controllers
[navigationController release];
[addController release];
}
The method insertNewObjectForEntityForName is returning a new instance of Place correctly when I try adding a place initially, but when I delete a place from the list then press "+" this method is called again and this time insertNewObjectForEntityForName returns the place that was just deleted.
Can anyone give me some ideas as to what is happening? I know this method returns an autoreleased object -- not sure if this has anything to do with it.
UPDATE: I think it's happening because right before the add view controller displays you can see the new object being inserted at the top of table view controller in the first row. When the add view controller is displayed the new object is indeed a new instance. Also, if I save this object it correctly replaces the row in the table view controller with the correct information. So maybe this has something to do with my table view below. Ahhh, I just figured it out and answered my own question. My cellForRowAtIndexPath was using a reused cell and the information was displaying the latest cell deleted. I've since fixed this. Thanks though for the reassurance it wasn't the code above.
That can't be happening given the code above. Why do you think that is what's happening? Add NSLog statements to output properties of newPlace after it has been inserted and before you present the navigationController to verify this. I would also do some logging in addController. Whatever is going on, the problem is likely there. What is the #property definition for the place property in addController? Add some more code and I'll try to help more.

Three20 comunication between datasource items and TTTableViewController

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

How do you change the detailViewController in a method

I have a view that is doing a lot of functions and when I get to the point that I am done I want to change to a newViewcontroller. if I where to do this from the rootview I just call.
NewPageViewController *newDetailViewController = [[NewPageViewController alloc] initWithNibName:#"NewPageViewController" bundle:nil];
detailViewController = newDetailViewController;
But I need to do it from my old detail (the right side)
I am downloading a file in a splitview iPad app from the right side and after the file is downloaded I need to in my method change the right side of the splitview to a new nib file so I can open and edit the file
Can someone point me in the right way.
Now I have :
-(void)changeView {
ListController *newDetailViewController = [[ListController alloc] initWithNibName:#"ListController"bundle:nil]
NSArray *viewControllers = [NSArray arrayWithObjects:[splitViewController.viewControllers objectAtIndex:0], newDetailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
}
-(void)downloadfile {
//I do all my work and get the file.
NSLog(#"I need to change views now.");
[self changeView];
}
I don't get any errors but the right side view is not changing.
As of iOS8 you can use the -showDetailViewController:sender: method on the UISplitViewController. See the Apple docs on UISplitViewController.
There is an NSArray *viewControllers property on the UISplitViewController class. The first item in this array is your master VC, the second in the detail VC. Re-assign this property to a new array containing the same master VC but a new details VC:
// don't forget to set the delegate of myNewDetailViewController appropriately!
myNewDetailViewController.delegate = ...
NSArray newVCs = [NSArray arrayWithObjects:[uiSplitVC.viewControllers objectAtIndex:0], myNewDetailViewController, nil];
uiSplitVC.viewControllers = newVCs;
API ref for UISplitViewController: http://developer.apple.com/library/ios/#documentation/uikit/reference/UISplitViewController_class/Reference/Reference.html
N.B: do not try replacing the master VC -- it usually goes horribly wrong somehow. I tried many many ways of replacing the master, it always went wrong in some very annoying way. Replacing the detail VC is fine though!
As #chris mentioned you can the use Delegate of UISplitViewController for iOS 8 and above which is the best possible way.
-(void)showDetailViewController:(UIViewController *)vc sender:(nullable id)sender NS_AVAILABLE_IOS(8_0);

taking string from a text field and passing it to the previous viewController

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];
}