UITableView not reloading on reloadData - ios

I have 2 views. The first one has the UITableView on it, it loads perfectly, and also if I click my logOut method which is triggered through didSelectRowAtIndexPath it works perfectly.
For the login I have another View, which loads on top as a modal view for Login. Once the login returns success I want it to refresh the menu on UITableView from the first view. Unfortunately this doesn't work.
MenuVC.h
#interface MenuVC : UIViewController<UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *mainNavigation;
-(void)logOut;
-(void)refreshMenu;
MenuVC.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Aanwezig in viewDidLoad");
NSUserDefaults *userData=[NSUserDefaults standardUserDefaults];
self.mainNavigation.dataSource = self;
self.mainNavigation.delegate = self;
self.mainNavigation.backgroundColor = [UIColor clearColor];
self.menu = [NSMutableArray arrayWithObjects:#"Login",#"Available", #"Downloads", #"FAQ", nil];
if ( [userData objectForKey:#"userId"] != nil ) {
[self.menu removeObject:#"Login"];
[self.menu insertObject:[userData objectForKey:#"email"] atIndex:0];
[self.menu insertObject:#"Logout" atIndex:1];
signedInSuccess = YES;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"menuCell";
MenuCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell=[[MenuCell alloc]initWithStyle:
UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
if ( signedInSuccess == YES && indexPath.row == 0 ) {
NSLog(#"Disabled: %#", [self.menu objectAtIndex:indexPath.row]);
cell.userInteractionEnabled = NO;
cell.menuTextLabel.adjustsFontSizeToFitWidth = YES;
} else {
cell.userInteractionEnabled = YES;
cell.menuTextLabel.adjustsFontSizeToFitWidth = NO;
}
cell.menuTextLabel.text = [self.menu objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Logout and refreshMenu both work here
if ( [identifier isEqualToString:#"Logout"] ) {
NSLog("Logout button clicked");
[self logOut];
[self refreshMenu];
}
//Rest of the code
}
-(void)refreshMenu {
[self viewDidLoad];
[self.mainNavigation reloadData];
}
-(void)logOut {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"userId"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"email"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"password"];
signedInSuccess = NO;
}
The codes above all work, only here is the problem occurring, when I click loginClicked, and call refreshMenu it IS doing [self viewDidLoad], but NOT [self.mainNavigation reloadData]; from the refreshMenu method.
LoginVC.m
#import "MenuVC.h"
- (IBAction)loginClicked:(id)sender {
{
// If login process is success (which works)
MenuVC *MenuViewController = [[MenuVC alloc] init];
[MenuViewController refreshMenu];
}

First of all:
You don't call yourself viewDidLoad. So remove it in refreshMenu, and if you want other code that you put in viewDidLoad transform it in a method that you'll call in viewDidLoad and that you could also call in refreshMenu
The issue, is that you have an object MenuVC already created. When in LoginVC.m you do MenuVC *MenuViewController = [[MenuVC alloc] init]; it's a whole new object. It isn't even on screen. That not the same object that the previous one. If you doubt it, check their pointers.
If I understood correctly, your MenuVC object is the owner of the LoginVC object.
So, a solution you can use is the delegate pattern.
Here a suggestion you can adapt.
In LoginVC.h
#protocol LoginVCDelegate < NSObject >
-(void)didLoginWithSuccess:(BOOL)success;
#end
#property (nonatomic, week) id < LoginVCDelegate > loginDelegate;
In LoginVC.m, in loginClicked:
if ([_loginDelegate respondsToSelector:#selector(didLoginWithSuccess:)])
[_loginDelegate didLoginWithSuccess:theBooleanYouWant];
In MenuVC.h
#interface MenuVC : UIViewController< UITableViewDelegate, UITableViewDataSource, LoginVCDelegate >
In MenuVC.m
-(void)didLoginWithSuccess:(BOOl)success
{
[self refreshMenu];
//Note that you could check if login succeed or not by checking the success boolean.
}
Also, when LoginVC is created in MenuVC.m:
[loginVC setLoginVCDelegate:self];

Related

How to get back textfield data from tableViewCell in objective c?

I have two tableViewControllers, second tableViewController tableViewCell has textField and imageView, how can I get data from that textfield when I click navigationBarBackButton (I want to store that data in first tableViewController).
// code from second tableViewController...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellID"];
cell.textLabel.text = #"SIM Name";
cell.detailTextLabel.text = #"AirTel";
cell.imageView.image = [UIImage imageNamed:#"Star2.png"];
return cell;
}
TableViewCell1 *cell1 = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
cell1.nameTextField.delegate = self;
if (indexPath.row == 1) {
NSArray *cell1XibRef = [[NSBundle mainBundle]loadNibNamed:#"TableViewCell1" owner:self options:nil];
cell1 = [cell1XibRef objectAtIndex:0];
cell1.imageView.image = [UIImage imageNamed:#"Con.png"];
self.nameString = cell1.nameTextField.text;
return cell1;
}
return nil;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
//Whenever people start editing your textfield
self.nameString = textField.text;
NSLog(#"%#", self.nameString);
}
So many ways to do that but I prefer this way
Save the textfield.text value in NSUserDefaults like this
[[NSUserDefaults standardUserDefaults] setObject:textField.text forKey:#"controllerTwo"];
And get that value in first controller
NSString *secondContrllerText = [[NSUserDefaults standardUserDefaults] stringForKey:#"controllerTwo"];
You can directly add cells in one array and loads cells from that array which will returns you latest cell with all your edits.
NSMutableArray *arrCells = [[NSMutableArray alloc] init];
for (init i=0; i<20; i++){
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"cellID"];
arrCells = cell;
}
In cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = arrCell[indexPath.row];
......
return cell;
}
here is the code i like to pass the data with block.here is the code wish to help you.
FirstViewController.h
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
#end
FirstViewController.m
#import "FirstViewController.h"
#import "ViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)buttonClick
{
ViewController *controller = [[ViewController alloc] init];
controller.passTheTextFieldData = ^(NSString *textValue){
NSLog(#"show the %# textValue",textValue);
};
[self.navigationController pushViewController:controller animated:YES];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (nonatomic, strong) void (^passTheTextFieldData)();
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()<UITextFieldDelegate>
#property (nonatomic, strong) UITextField *textField;
#property (nonatomic, strong) NSString *textValue;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[self.textField addTarget:self action:#selector(textFieldValueChanged) forControlEvents:UIControlEventValueChanged];
}
- (void)textFieldValueChanged
{
self.textValue = self.textField.text;
}
- (void)navigationbarBackClick
{
if (self.passTheTextFieldData) {
self.passTheTextFieldData(self.textValue);
}
}
#end
Set the tag property for textField in tableViewCell
Then loop through the cells
for (int i = 0 ; i < [cellDataArray count] ; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UITextField *txtfield = [[cell contentView]viewWithTag:2];
//now get the text txtfield.text
}
Hope this helps
Either you can use delegate method to store your value or use NSUserdefaults.But you have to store one value to pass it to another table view i recommend you to use NSUserdefaults.
//suppose you have to save text (get your data)
NSString *valueToSave = cell1.nameTextField.text;
[[NSUserDefaults standardUserDefaults] setObject:valueToSave forKey:#"keyAbcd"];
[[NSUserDefaults standardUserDefaults] synchronize];
//another page where you want to show your data (paste your data)
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"keyAbcd"];//your key have to be same
//print save value in nslog

List not being populated from other view

I have a view controller where the user can populate an item. Upon exiting the view that object should be saved, and loaded by the previous view which contains a list of all these objects. My NSLog shows that the object is being saved, but I can't get it to appear in the list view.
Code for both controllers is below. Thanks
List Controller
#import "ItemsViewController.h"
#import "Calculation.h"
#import "CalculationItemStore.h"
#import "CalculationDetailViewController.h"
#interface ItemsViewController()
#property UISegmentedControl *segment;
#end
#implementation ItemsViewController
- (instancetype)init
{
// Call the superclass's designated initializer
self = [super initWithStyle:UITableViewStylePlain];
if (self) {
UINavigationItem *navItem = self.navigationItem;
navItem.title = #"MACS";
// Create a new bar button item that will send
// addNewItem: to CalculationsViewController
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self
action:#selector(addNewItem:)];
// Set this bar button item as the right item in the navigationItem
navItem.rightBarButtonItem = bbi;
navItem.leftBarButtonItem = self.editButtonItem;
}
return self;
}
- (instancetype)initWithStyle:(UITableViewStyle)style
{
return [self init];
}
- (void)viewDidLoad
{
self.segment = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Publication", #"About", nil]];
self.tableView.tableHeaderView = _segment;
[_segment addTarget:self action:#selector(segmentPressed:) forControlEvents:UIControlEventValueChanged];
[self.tableView registerClass:[UITableViewCell class]
forCellReuseIdentifier:#"UITableViewCell"];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[CalculationItemStore sharedStore] allCalculations] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Get a new or recycled cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell" forIndexPath:indexPath];
// Set the text on the cell with the description of the item
// that is at the nth index of items, where n = row this cell
// will appear in on the tableview
NSArray *items = [[CalculationItemStore sharedStore] allCalculations];
Calculation *item = items[indexPath.row];
cell.textLabel.text = item.title;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CalculationDetailViewController *detailViewController = [[CalculationDetailViewController alloc] init];
NSArray *items = [[CalculationItemStore sharedStore] allCalculations];
Calculation *selectedItem = items[indexPath.row];
// Give detail view controller a pointer to the item object in row
detailViewController.calculation = selectedItem;
// Push it onto the top of the navigation controller's stack
[self.navigationController pushViewController:detailViewController
animated:YES];
}
- (void) tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
// If the table view is asking to commit a delete command...
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSArray *items = [[CalculationItemStore sharedStore] allCalculations];
Calculation *item = items[indexPath.row];
[[CalculationItemStore sharedStore] removeItem:item];
// Also remove that row from the table view with an animation
[tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void) tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toIndexPath:(NSIndexPath *)destinationIndexPath
{
[[CalculationItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row
toIndex:destinationIndexPath.row];
}
- (void)segmentPressed:(id)sender {
if (_segment.selectedSegmentIndex ==0) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://ferm.forestry.oregonstate.edu/facstaff/leshchinsky-ben"]];
}else if(_segment.selectedSegmentIndex ==1){
UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)];
imageView.backgroundColor = [UIColor redColor];
[imageView setImage: [UIImage imageNamed:#"MACSLoad#2x.png"]];
[self.view addSubview: imageView];
sleep(5);
imageView.hidden = YES;
}
}
- (IBAction)addNewItem:(id)sender
{
// Create a new Calculation and add it to the store
Calculation *newItem = [[CalculationItemStore sharedStore] createCalculation];
CalculationDetailViewController *detailViewController = [[CalculationDetailViewController alloc]initForNewItem:YES];
detailViewController.calculation = newItem;
detailViewController.dismissBlock = ^{
[self.tableView reloadData];
};
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:detailViewController];
navController.modalPresentationStyle = UIModalPresentationFullScreen;
// [self presentViewController:navController animated:YES completion:NULL];
[self.navigationController pushViewController:detailViewController animated:YES];
}
#end
Item controller save method
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
//clear responder
[self.view endEditing:YES];
//save changes
BOOL success = [[CalculationItemStore sharedStore]saveChanges];
if(success){
NSLog(#"Saved all calcs");
}else{
NSLog(#"failure saving");
}
}
I think the issue is that by the time the table reloadData is called on the first controller, the second one is not done loading. You could notify the first VC to reload the data once the second one is done saving It can be notified using
create a delegate on the second one or
using notifications
Let me know if you need more details on how to do this!
Looks like there is also an issue with the object creation.
your calculation elements are not getting created properly. When you are ready to save.. look at the contents of self.privateItems. They values filled in are nil. You will need to instantiate the Strings properly.
engineerName needs to be alloc'd and other strings as well.
and when user hits Done, the values from the text boxes need to be set to the your data model.

Passing data from dynamic tableview back to static tableview

Please help i have been struggling passing back the data. I have 2 tableViews. 1st tableview=static table=RootVC. 2nd tableview=dynamic table=FirstVC. in RootVC i have a cell with two labels, "repeatLabel" and "repeatDetail" with a disclosure indicator. When i click on the cell it display the next table which is FirstVC, FistVC is populated with weekdays. after selection of my choice, i want the selected days to be passed back into RootVC in "repeatDetail" and when i go back still be able to see previously selected data.
My RootVC looks like this:
#import "RepeatViewController.h"
#interface SettingsViewController : UITableViewController
#property (strong, nonatomic) IBOutlet UILabel *repeatDetail;
#property (strong, nonatomic) IBOutlet UILabel *repeatLabel;
#property (strong,nonatomic) NSString *getRepeatDetail;
#property (nonatomic, strong) NSMutableArray *selectedDaysArray;
#end
in my RootVC.m
#import "SettingsViewController.h"
#interface SettingsViewController ()
#end
#implementation SettingsViewController
#synthesize repeatLabel,repeatDetail;
#synthesize getRepeatLabel;
#synthesize selectedDaysArray;
- (void)viewDidLoad
{
[super viewDidLoad];
repeatLabel.text = #"Repeat";
repeatDetail.text = getRepeatLabel;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
RepeatViewController *destinationController = segue.destinationViewController;
if( [destinationController isKindOfClass:[RepeatViewController class]] )
{
//You can reuse your selectedDays arrays
destinationController.selectedDays = self.selectedDaysArray;
[(RepeatViewController *)destinationController setCompletionBlock:^(NSArray *retDaysArray) // <- make this change
{
// Save your changes
self.selectedDaysArray = [NSMutableArray arrayWithArray: retDaysArray]; // <- make this change
NSLog(#"retDaysArray: %#", self.selectedDaysArray); //<- Add this debug line
}];
}
}
#end
My 1stVC.h
#import "SettingsViewController.h"
typedef void(^WeekdayCompletionBlock)(NSArray *retDaysArray);
#interface RepeatViewController : UITableViewController <UITableViewDataSource,UITableViewDelegate>
#property (nonatomic,strong) NSMutableArray *selectedDays;
#property (nonatomic, copy) NSArray *completionBlock;
#property (copy) WeekdayCompletionBlock returnBlock;
//#property (strong, nonatomic) IBOutlet UIBarButtonItem *saveButton;
-(IBAction)save:(id)sender;
#end
my 1stVC.m
#import "RepeatViewController.h"
#interface RepeatViewController ()
#end
#implementation RepeatViewController
#synthesize selectedDays= _selectedDays;
#synthesize completionBlock;
#synthesize returnBlock;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
completionBlock = [NSArray arrayWithObjects:#"Sunday", #"Monday", #"Tuesday", #"Wednesday", #"Thursday", #"Friday", #"Saturday", nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (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 7;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"RepeatCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
}
NSString *day = completionBlock[indexPath.row];
cell.textLabel.text = day;
if ([self.selectedDays containsObject:day])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
//cell.textLabel.text = [completionBlock objectAtIndex:indexPath.row];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (!self.selectedDays)
self.selectedDays = [[NSMutableArray alloc] init];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
//remove data from array
[self.selectedDays removeObject:[completionBlock objectAtIndex:indexPath.row]];
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//add data to array
[self.selectedDays addObject:[completionBlock objectAtIndex:indexPath.row]];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
-(IBAction)save:(id)sender
{
NSUserDefaults *myNewWeekString = [NSUserDefaults standardUserDefaults];
[myNewWeekString setObject:self.selectedDays forKey:#"MY_KEY_FOR_ACCESING_DAYSOFWEEK"];
[myNewWeekString synchronize];
//NSLog(#"The selected day/s is %#",self.selectedDays);
if (self.returnBlock)
{
self.returnBlock(self.selectedDays);
}
[self.navigationController popViewControllerAnimated:YES];
// NSLog(#"The selected day/s is %#",self.selectedDays);
// if (self.returnBlock)
// {
// self.returnBlock([completionBlock objectAtIndex:indexPath.row]);
//}
}
/*
-(void) setReturnBlock:(WeekdayCompletionBlock)returnBlock
{
[self.selectedDays addObject:(self.returnArray);
}
- (NSArray *)setDats
{
return [NSArray arrayWithArray:[self.selectedDays copy]];
}*/
#end
When you work with static cells you have to bind the control you are using directly, there's no need.
So what I can suggest you is the following:
Bind your controls with some specific identifier, like labelFieldRow{rowid} example: labelFieldRow1.
So on prepare for segue, just check what's the selected row and pass the data you want to the destination controller.
Probably not the best, but it should work.
You have to pass data (selected by user before) from your RootVC to FirstVC. To do that in your RootVC add property to keep the selected data;
#property (nonatomic, strong) NSMutableArray *selectedDaysArray;
In prepareForSegue method you have to pass that array to let the table view know what needs to be selected:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationController = segue.destinationViewController;
if( [destinationController isKindOfClass:[RepeatViewController class]] )
{
//You can reuse your selectedDays arrays
((RepeatViewController*)destinationController).selectedDays = self.selectedDaysArray;
[(RepeatViewController *)destinationController setReturnBlock:^(NSArray *retDaysArray) // <- make this change
{
// Save your changes
self.selectedDaysArray = [NSMutableArray arrayWithArray: retDaysArray]; // <- make this change
NSLog(#"DATA: %#", self.selectedDaysArray) //<- Add this debug line
}];
}
}
Remove this line from viewDidLoad you don't want to allocate it every time now you just pass it from rootVC
_selectedDays = [[NSMutableArray alloc] init];
And in cellForRowInIndexPath replace this line:
cell.textLabel.text = [completionBlock objectAtIndex:indexPath.row];
with this code:
NSString *day = completionBlock[indexPath.row];
cell.textLabel.text = day;
if ([self.selectedDays containsObject:day])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
And change didSelectRowAtIndexPath: to
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (!self.selectedDays)
self.selectedDays = [[NSMutableArray alloc] init];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
//remove data from array
[self.selectedDays removeObject:[completionBlock objectAtIndex:indexPath.row]];
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//add data to array
[self.selectedDays addObject:[completionBlock objectAtIndex:indexPath.row]];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Hope this help.

iOS partial screen dialog for drop down listbox (android spinner) style control

In iOS for the iPhone I want to make a control with similar appearance and behavior to the android spinner control when configured to behave like a drop down list box. Specifically when pressed a modal list of text options with radio buttons comes up and when one of them is pressed the list disappears and the control updates to that choice. Example:
So far I have seen a full-screen option using [self presentViewController...] with a custom ViewController but I want a partial screen (like pictured above) solution. Does anyone know how to do this or could point in the right direction.
The native solution to this will be a UIActionSheet which on iPhone will appear from the bottom and be partial screen or on iPad be very similar to the android version.
You can find the documentation here: UIActionSheet
if you didnt want to use the UIActionSheet and you wanted to make it reusable rather than adding a whole bund of UIViews to your current XIB, you could create a custom UIView with whatever interface you would need to populate it and use the interface builder to help make it look ok.
that view could have a message handler that posts the response that you would need to listen for.
then just init and load the view into your subviews and populate it
then post a message from the custom view to the handler you registered
so for your custom view you would have something like this.
#implementation SomeCustomView
+(SomeCustomView*)viewFromNibNamed:(NSString *)nibName{
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:NULL];
NSEnumerator *nibEnumerator = [nibContents objectEnumerator];
SomeCustomView *customView = nil;
NSObject* nibItem = nil;
while ((nibItem = [nibEnumerator nextObject]) != nil) {
if ([nibItem isKindOfClass:[AADropDown class]]) {
customView = (SomeCustomView*)nibItem;
break;
}
}
return customView;
}
-(void)someInitializationWith:(NSArray*)repeatableData andNotificationId:(NSString*)noteId{
//set your stuff up for the view here and save the notification id
}
...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[[NSNotificationCenter defaultCenter] postNotificationName:Your_Notification_Id object:somevalue];
}
#end
and include other things, like in this case the tableview stuff or any other logic.
then in your viewcontroller you could call it like
__block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:#"customViewAction" object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) {
//deal with notification here
[[NSNotificationCenter defaultCenter] removeObserver: observer];
}];
SomeCustomView *cv =(SomeCustomView*) [SomeCustomView viewFromNibNamed:#"SomeCustomView"];
[cv someInitializationWith:arrayOptions andNotificationId:#"customViewAction"];
[self.view addSubview:cv];
and in your interface builder you will just need to make sure that the class of the view is set to your class type.
then you can easily reuse this code again whenever a user needs to select something else in the same manner.
Here is a variation on the solution suggested by AtomRiot.
On your view (xib or storyboard) make a button and assign this graphic to it. Don't worry if it appears stretched out in the editor. The code will make it a realizable graphic.
2X version
Then include the following files in your project (copied below):
DDLBHelper.h
DDLBHelper.m
Then in your ViewController's .h file make links to the button:
#property (weak, nonatomic) IBOutlet UIButton *ddlbB;
- (IBAction)ddlbBClick:(id)sender;
In you ViewController's .m file make the following calls:
#synthesize ddlbB, choiceLabel;
DDLBHelper *mDDLBH;
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *strings = [[NSArray alloc] initWithObjects:#"Item 1", #"Item 2", #"Item 3", nil];
mDDLBH = [[DDLBHelper alloc] initWithWithViewController:self button:ddlbB stringArray:strings currentValue:1];
}
- (IBAction)ddlbBClick:(id)sender {
[mDDLBH popupList];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[mDDLBH adjustToRotation];
}
Works just like android.
Here are the files:
DDLBHelper.h
// DDLBHelper.h
// Created by MindSpiker on 9/27/12.
#import <Foundation/Foundation.h>
#protocol DDLBHelperDelegate <NSObject>
#required
- (void) itemSelected: (int)value;
#end
#interface DDLBHelper : UIViewController <UITableViewDelegate, UITableViewDataSource>{
id <DDLBHelperDelegate> delegate;
}
#property (retain) id delegate;
// external interface
- (id) init;
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue;
- (void) popupList;
- (BOOL) isShown;
- (void) adjustToRotation;
- (int) getValue;
- (NSString *)getValueText;
#end
DDLBHelper.m
// DDLBHelper.m
// Created by MindSpiker on 9/27/12.
#import "DDLBHelper.h"
#import <QuartzCore/QuartzCore.h>
#interface DDLBHelper () {
#private
UIViewController *mVC;
UIButton *mButton;
NSArray *mValues;
int mValue;
UITableView *mTV;
UIView *mBackgroundV;
}
#end
#implementation DDLBHelper
#synthesize delegate;
- (id) init {
self = [super init];
mVC = nil;
mButton = nil;
mValues = nil;
mValue = -1;
return self;
}
- (id) initWithWithViewController:(UIViewController *)viewController button:(UIButton *)button stringArray:(NSArray *)values currentValue:(int) currentValue {
self = [super init];
// save pointers
mVC = viewController;
mButton = button;
mValues = values;
mValue = currentValue;
[self setupButton];
return self;
}
- (void) popupList{
if (mBackgroundV == nil){
mBackgroundV = [self setupBackgroundView];
[mVC.view addSubview:mBackgroundV];
}
if (mTV == nil){
mTV = [self setupTableView];
[mVC.view addSubview:mTV];
}
[mTV reloadData];
[mBackgroundV setHidden:NO];
[mTV setHidden:NO];
}
- (BOOL) isShown{
return !mTV.isHidden;
}
- (void) adjustToRotation{
BOOL isShown = [self isShown];
// remove the controls
if (mBackgroundV != nil){
[mBackgroundV removeFromSuperview];
mBackgroundV = nil;
}
if (mTV != nil){
[mTV removeFromSuperview];
mTV = nil;
}
if (isShown){
[self popupList];
}
}
- (int) getValue{
return mValue;
}
- (NSString *) getValueText{
if (mValues != nil && mValue > -1) {
if (mValues.count > mValue){
return [mValues objectAtIndex:mValue];
}
}
return nil;
}
- (void) updateButtonTitle{
NSString *title = [NSString stringWithFormat:#" %#", [self getValueText]];
[mButton setTitle:title forState:UIControlStateNormal];
}
- (void) setupButton {
UIImage *buttonBG = [UIImage imageNamed:#"sis_proceeds_ddlb.png"];
UIEdgeInsets insets = UIEdgeInsetsMake(8, 8, 8, 45);
UIImage *sizableImg = [buttonBG resizableImageWithCapInsets:insets];
[mButton setBackgroundImage:sizableImg forState:UIControlStateNormal];
[mButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[self updateButtonTitle];
}
- (UIView *) setupBackgroundView{
UIView *v = [[UIView alloc] initWithFrame:mVC.view.bounds];
[[v layer] setOpaque:NO];
[[v layer] setOpacity:0.7f];
[[v layer] setBackgroundColor:[UIColor blackColor].CGColor];
return v;
}
- (UITableView *) setupTableView {
CGRect rect = [self makeTableViewRect];
UITableView *tv = [[UITableView alloc] initWithFrame:rect style:UITableViewStylePlain];
[tv setDelegate:self];
[tv setDataSource:self];
[tv setBackgroundColor:[UIColor whiteColor]];
[[tv layer] setBorderWidth:2];
[[tv layer] setBorderColor:[UIColor lightGrayColor].CGColor];
[[tv layer] setCornerRadius:10];
[mVC.view addSubview:tv];
return tv;
}
- (CGRect) makeTableViewRect {
float l=0.0, t=0.0, w=0.0, h=0.0, maxH=0.0, cellH=0.0, cellsH=0.0;
// get
l = mButton.frame.origin.x;
w = mButton.frame.size.width;
t = mVC.view.bounds.origin.y + 50;
maxH = mVC.view.bounds.size.height - 100;
// get cell height
UITableViewCell *c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cellH = c.bounds.size.height;
// see if list will overlow maxH(eight)
cellsH = cellH * mValues.count;
if (cellsH > maxH) {
h = maxH;
} else {
h = cellsH;
}
return CGRectMake(l, t, w, h);
}
#pragma mark - TableView Delegate functions
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1; // this is a one section table
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return mValues.count; // should be called for only one section
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// try to resuse a cell if possible
static NSString *RESUSE_IDENTIFIER = #"myResuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:RESUSE_IDENTIFIER];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:RESUSE_IDENTIFIER];
}
cell.textLabel.text = [mValues objectAtIndex:indexPath.row];
if (mValue == indexPath.row){
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// save value and hide view
mValue = indexPath.row;
[self updateButtonTitle];
[mBackgroundV setHidden:YES];
[mTV setHidden:YES];
[delegate itemSelected:mValue];
}
#end

Data not loading in Detail View

I'm trying to get my data to load in my detail view. Can any one take a look and see why it isnt showing? It loads fine in my rootviewcontroller, just not the detail view.
DetailViewController.m
#import "DetailViewController.h"
#implementation DetailViewController
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)setIcon:(UIImage *)newIcon
{
[super setIcon:newIcon];
iconView.image = newIcon;
}
- (void)setPublisher:(NSString *)newPublisher
{
[super setPublisher:newPublisher];
publisherLabel.text = newPublisher;
}
- (void)setName:(NSString *)newName
{
[super setName:newName];
nameLabel.text = newName;
}
- (void)dealloc
{
[iconView release];
[publisherLabel release];
[nameLabel release];
[priceLabel release];
[super dealloc];
}
#end
detailviewcontroller.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface DetailViewController : UIViewController {
IBOutlet UIImageView *iconView;
IBOutlet UILabel *publisherLabel;
IBOutlet UILabel *nameLabel;
IBOutlet UILabel *priceLabel;
}
#end
RootViewControllerPoints.m
#import "RootViewControllerPoints.h"
#import "DetailViewController.h"
#define USE_INDIVIDUAL_SUBVIEWS_CELL 1
#define DARK_BACKGROUND [UIColor colorWithRed:151.0/255.0 green:152.0/255.0 blue:155.0/255.0 alpha:1.0]
#define LIGHT_BACKGROUND [UIColor colorWithRed:172.0/255.0 green:173.0/255.0 blue:175.0/255.0 alpha:1.0]
#implementation RootViewController
#synthesize tmpCell, data;
#pragma mark View controller methods
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the table view.
self.tableView.rowHeight = 73.0;
self.tableView.backgroundColor = DARK_BACKGROUND;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
// Load the data.
NSString *dataPath = [[NSBundle mainBundle] pathForResource:#"Data" ofType:#"plist"];
self.data = [NSArray arrayWithContentsOfFile:dataPath];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
return YES;
default:
return NO;
}
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ApplicationCell";
ApplicationCell *cell = (ApplicationCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
#if USE_INDIVIDUAL_SUBVIEWS_CELL
[[NSBundle mainBundle] loadNibNamed:#"IndividualSubviewsBasedApplicationCell" owner:self options:nil];
cell = tmpCell;
self.tmpCell = nil;
#endif
}
// Display dark and light background in alternate rows -- see tableView:willDisplayCell:forRowAtIndexPath:.
cell.useDarkBackground = (indexPath.row % 2 == 0);
// Configure the data for the cell.
NSDictionary *dataItem = [data objectAtIndex:indexPath.row];
cell.icon = [UIImage imageNamed:[dataItem objectForKey:#"Icon"]];
cell.publisher = [dataItem objectForKey:#"Publisher"];
cell.name = [dataItem objectForKey:#"Name"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detailViewController. = [data objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
#end
This has been bugging me for quite a while, I've looked at numerous examples, tutorials and even asked other iphone devs. Everything source seems to say something different.
First problem is that the setXXX methods in DetailViewController try to make calls to super setXXX but since DetailViewController is a subclass of UIViewController those calls to super will fail because UIViewController doesn't have such methods. Remove the calls to super in the setXXX methods.
Second problem is that the setXXX methods are setting the controls on the DetailViewController directly but the controls won't be accessible until the view is loaded so it won't work if the methods are called before the pushViewController call.
If you change the code in didSelectRowAtIndexPath as follows it should work:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController setName:#"name here"];
[detailViewController setPublisher:#"publisher here"];
[detailViewController setIcon:yourImageVariableHere];
[detailViewController release];
}
Although the above change should work, you might want to consider creating ivars to hold the values in DetailViewController (instead of using the ui controls themselves to hold the data). Then create properties for them using #property and #synthesize. The properties can be set immediately after DetailViewController is created and in the viewDidLoad of the view, you can set the ui controls to the property values. This will give the DetailViewController more control over how its ui is updated, allow you to change the ui without affecting callers, and it doesn't need to be displayed to set its properties.

Resources