How to pass variable from UIViewController to dele

2019-07-11 07:12发布

I'm relatively new to iOS programming, so bear with me here. The requirement I'm working with is as follows:

Screen 1: User is shown a UITableView loaded with data, specifically City and State. The user taps on a selection and is taken to Screen 2.

Screen 2: The user is shown a "detailed" view of the item they selected for editing.

  • The City string (selectedCity) is placed in a Text Box for editing
  • An NSArray of States is loaded in a UITableView. The state for the selected City should be selected in the table on load based on the string passed from Screen 1 (selectedState). The user can select a different State here if desired.
  • A 2nd UITableView will contain an array of Schools related to the city and retrieved from the database. There is a separate set of functionality for managing this list.

I have not had any issues implementing Screen 1. Here's how I passed the city and state values through to screen 2:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    //Get the City
    self.checkedCellIndex = indexPath.row;
    FSCity *selectedCity = [CityList objectAtIndex:indexPath.row];
    NSString *cityName = selectedCity.name;
    NSString *stateName = selectedCity.state;

    AdminCityView *dvController = [[AdminCityView alloc] initWithNibName:@"AdminCityView" bundle:[NSBundle mainBundle]];
    dvController.selectedCity = cityName;
    dvController.selectedState = stateName;

    [self.navigationController pushViewController:dvController animated:YES];

    dvController = nil;
}

In order to build Screen 2, however, I had to create UITableViewControllers for each UITableView (StateTable and SchoolTable) and load them in to the main UIViewController (AdminCityView), like so:

- (void)viewDidLoad
{
    [super viewDidLoad];

    txtCity.text = selectedCity;

    if (stateController == nil) {
        stateController = [[StateTable alloc] init];
    }
    if (schoolController == nil) {
        schoolController = [[SchoolTable alloc] init];
    }
    [tblState setDataSource:stateController];
    [tblSchool setDataSource:schoolController];

    [tblState setDelegate:stateController];
    [tblSchool setDelegate:schoolController];
    stateController.view = stateController.tableView;
    schoolController.view = schoolController.tableView; 
}

While I can get at the selectedState variable just fine in my UIViewController and my State table loads just fine in the UIView, I'm stuck at how to pass the selectedState variable from my UIViewController (AdminCityView) to the UITableViewController (StateTable) so that I can perform operations on StateTable with the variable (such as selecting the row that matches the variable).

I've been testing with NSLog on both AdminCityView and StateTable, and the variable is definitely only accessible from AdminCityView currently. I'm not sure if I need to pass it via code in AdminCityView, or if I should just go back to Screen 1 and somehow pass it to StateTable prior to navigating to AdminCityView.

I'm happy to post any additional code that might be helpful toward reaching an answer. Thanks!

1条回答
劳资没心,怎么记你
2楼-- · 2019-07-11 07:33

There are 3 ways to get this done, pick yours.

If you are using storyboard, you can just use a segue and be done with it. From your code i can only guess that you aren't, since viewController:initWithNibName would be unneccesary then.

So you are kind of stuck with the old ways, which turn out to be the best at some times...

You could use a notification via the NSNotificationCenter. You subscribe your your stateTable to the notificationCenter using

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someMethodToCall:) name:@"someName" object:nil];

where observer should be self, selector is a method you must implement that will get called when the notification is send (you can choose hat name as you wish), name is the name of the notification (choose as you like), and object is the object you want to receive Notifications from (you probably dont need to specify this one, unless you send a lot of Notifications).

Also you need to implement -(void)someMethodToCall: like this:

-(void)someMethodToCall:(NSNotification *)notification{
    NSDictionary *dic = notification.userInfo;
    //you will store all the data you want transferred in this, as you will see.
    //use it as you like
}

Your AdminCityView now can send messages to your stateTable, and those can carry payloads. All you need to do is:

[self postNotificationName:@"theNameYouChoseAbove" object:yourFirstViewController  userInfo:someDictionaryThatHoldsYourValues];

Now Data from AdminCityView is transferred in a NSDictionary. Those things are really open-minded about stuff they accept, so you should be fine.

Another way is to use a protocol.

You can implement a protocol in AdminCityView like so:

@protocol yourNameHereProtocol
-(void)methodToCall:(NSString*)theData;
@end

just do it above the interface in the header file, use whatever type of data suits you. NSString is just an example.

Now stateController needs to conform to that protocol. in stateController.h add this behind the interface:

@interface stateController (UIViewController)<yourNameHereProtocol>{
}
-(void)someMethodToCall:(NSString *)theData;

Now stateController needs to implement someMethodToCall, where you process theData and you are halfway there.

Now, do this after creating dvController:

[dvController setDelegate:stateController];

Now, dvController can call the delegate method someMthodToCall:data in stateController, transmitting the data via the data-attribute.

Oh, and you really dont need two TableViewControllers, you can just conform the surrounding view to the UITableViewDataSource and TableViewDelegate protocols and handle all the different cases in the delegate methods. But thats for another post, i guess.

If you have any questions, please comment on this, and i will answer as good as i can. Also, i may have mixed up the denominators for your different Classes and such, feel free to change them as ist seems reasonable.

Have fun

查看更多
登录 后发表回答