iOS Replace Keyboard with UIPickerView then Back to Keyboard - ios

I have a textfield in my app in which a user can choose a Group they belong to, along with several other fields. When they get to the Group TextField, it pops up a UIPickerView that has several choices that have already been created, along with an option to "Create New Group". When that option is chosen, I want the UIPickerView to go away, and have the keyboard pop back up so they can type again. I can get the picker view to appear and to go away, but can't get the keyboard back. Here is code so far.
-(void)addPickerView{
__block NSMutableArray *arr = [[NSMutableArray alloc] init];
PFQuery *rejectedNumber = [PFQuery queryWithClassName:#"Group"];
[rejectedNumber orderByAscending:#"GroupName"];
[rejectedNumber findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!objects) {
// Did not find any UserStats for the current user
NSLog(#"NotFound");
} else {
pickerArray = objects;
[myPickerView reloadAllComponents];
}
}];
//pickerArray = GoGo;
self.theView.signUpView.additionalField.delegate = self;
[self.theView.signUpView.additionalField setPlaceholder:#"Choose Group"];
myPickerView = [[UIPickerView alloc]init];
myPickerView.dataSource = self;
myPickerView.delegate = self;
myPickerView.showsSelectionIndicator = YES;
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]
initWithTitle:#"Done" style:UIBarButtonItemStyleDone
target:self action:#selector(finishIt)];
UIToolbar *toolBar = [[UIToolbar alloc]initWithFrame:
CGRectMake(0, self.view.frame.size.height-
self.theView.signUpView.additionalField.frame.size.height-50, 320, 50)];
[toolBar setBarStyle:UIBarStyleBlackOpaque];
NSArray *toolbarItems = [NSArray arrayWithObjects:
doneButton, nil];
[toolBar setItems:toolbarItems];
self.theView.signUpView.additionalField.inputView = myPickerView;
self.theView.signUpView.additionalField.inputAccessoryView = toolBar;
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component{
return [pickerArray count] + 1;
}
#pragma mark- Picker View Delegate
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:
(NSInteger)row inComponent:(NSInteger)component{
if (row == 0)
[self.theView.signUpView.additionalField.inputView removeFromSuperview];
[self.theView.signUpView.additionalField becomeFirstResponder];
}
else {
[self.theView.signUpView.additionalField setText:self.theGroup];
}
}
- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *groupName = #"Create New Group";
if (row != 0)
{
PFObject *object = pickerArray[row - 1]; // -1 to handle the array index
self.theGroup = object[#"GroupName"];
groupName = object[#"GroupName"];
}
return groupName;
}

First thing i noticed is, you missed a braces here after if condition:
if (row == 0)
[self.theView.signUpView.additionalField.inputView removeFromSuperview];
[self.theView.signUpView.additionalField becomeFirstResponder];
}
Instead use this:
if (row == 0) {
[self.theView.signUpView.additionalField resignFirstResponder];
self.theView.signUpView.additionalField.inputView = nil;
[self.theView.signUpView.additionalField becomeFirstResponder];
}

Related

Right bar button item not show without first time

This is first time, edit button visible. But when i come from another tab edit button not visible, but if i press there it will visible. In my UITableView i use a rightBarButton Edit item in UINavigationBar. But it show's only first time. When I come from another tab to this tab next time, it's not shown. If i press in that place of that button it become shown. What is the problem?
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStylePlain target:self action:#selector(editActionOfTable) ];
-(void)editActionOfTable{
if (isEdited) {
isSelctedAll = NO;
[self.selectallButton setTitle:#"Select All" forState:UIControlStateNormal];
self.navigationItem.rightBarButtonItem.title = #"Edit";
//[self.editButton setTitle:#"Edit" forState:UIControlStateNormal];
[self.tableView setEditing:NO animated:YES];
[self customViewHide:YES];
isEdited = NO;
isDeleteButtonPress = false;
self.navigationItem.hidesBackButton = NO;
flagForCustomCell = false;
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:#"bottom" forKey:#"pos_Key"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"ad_banner" object:nil userInfo:userInfo];
}
else{
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:#"top_of_tab" forKey:#"pos_Key"];
[[NSNotificationCenter defaultCenter] postNotificationName: #"ad_banner" object:nil userInfo:userInfo];
flagForCustomCell = true;
//disable delete button when array empty
[self.deleteButtonOutlet setEnabled:NO];
self.deleteButtonOutlet.alpha = 0.5;
//disable fav button when array empty
[self.favInHistoryOutlet setEnabled:NO];
self.favInHistoryOutlet.alpha = 0.5;
self.navigationItem.rightBarButtonItem.title = #"Done";
//[self.editButton setTitle:#"Done" forState:UIControlStateNormal];
[self customViewHide:NO];
isDeleteButtonPress = true;
[self.tableView setEditing:YES animated:YES];
self.navigationItem.hidesBackButton = YES;
isEdited = YES;
}
}
This is my ViewWillAppear code:
-(void)viewWillAppear:(BOOL)animated{
self.navigationItem.rightBarButtonItem.tintColor = [UIColor whiteColor];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"History"];
self.devices = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
self.devices=[[[self.devices reverseObjectEnumerator] allObjects] mutableCopy];
NSFetchRequest *fetchRequest1 = [[NSFetchRequest alloc] initWithEntityName:#"Favourite"];
self.fvrt = [[managedObjectContext executeFetchRequest:fetchRequest1 error:nil] mutableCopy];
self.fvrt=[[[self.fvrt reverseObjectEnumerator] allObjects] mutableCopy];
[self setHeightForSpecificRow];
isDeleteButtonPress = false;
if(self.segmentControl.selectedSegmentIndex == 0){
segment = self.devices.count;
if(segment == 0){
self.navigationItem.rightBarButtonItem.enabled = NO;
self.tableView.hidden = YES;
emptyView.hidden = NO;
if(IS_DEVICE_IPAD){
[noHistoryFavImage setImage:[UIImage imageNamed:#"no-history-ipad.png"]];
}
else{
[noHistoryFavImage setImage:[UIImage imageNamed:#"no-history-iphone.png"]];
}
emptyViewLabel1.text = #"You do not have any translation history right now.";
}
else{
self.navigationItem.rightBarButtonItem.enabled = YES;
self.tableView.hidden = NO;
emptyView.hidden = YES;
}
}
else{
segment = self.fvrt.count;
if(segment == 0){
self.navigationItem.rightBarButtonItem.enabled = NO;
self.tableView.hidden = YES;
emptyView.hidden = NO;
if(IS_DEVICE_IPAD){
[noHistoryFavImage setImage:[UIImage imageNamed:#"heart-ipad.png"]];
}
else{
[noHistoryFavImage setImage:[UIImage imageNamed:#"heart-iphone.png"]];
}
emptyViewLabel1.text = #"You do not have any favorites right now.";
}
else{
self.navigationItem.rightBarButtonItem.enabled = YES;
self.tableView.hidden = NO;
emptyView.hidden = YES;
}
}
[self.tableView reloadData];
//self.navigationController.navigationBar.tintColor = [UIColor redColor];
}

UITableView sorting

I've been brought in on this project where the previous developers made custom table cells and headers by using xib files and then registering the nibs like so:
[self.accountTable registerNib:[UINib nibWithNibName:kNonATITableViewCellLandscapeNib bundle:[NSBundle mainBundle]] forCellReuseIdentifier:kNonATITableViewCellLandscapeIdentifier];
[self.accountTable registerNib:[UINib nibWithNibName:kNonATITableHeaderLandscapeNib bundle:[NSBundle mainBundle]] forCellReuseIdentifier:kNonATITableHeaderLandscapeId];
The header files have buttons in them and uiimageviews. The buttons are for sorting, the uiimageviews for an arrow icon to show you the direction of the sort (asc, desc). All the buttons and imageviews are IBOutlets. All the buttons are linked to an IBAction:
- (IBAction)sortButtonTouched:(id)sender;
The file also has two other properties:
#property (nonatomic, assign) SortType currentSortingOption;
#property (nonatomic, strong) UIButton* btnLastTouched;
Here is sortButtonTouched:
- (IBAction)sortButtonTouched: (UIButton*) buttonTouched {
if (!self.btnLastTouched) {
self.btnLastTouched = buttonTouched;
}
NSString* strFieldToSort;
UIImageView* ivSortImage;
NSArray* arrSortIcons = [[NSArray alloc] initWithObjects:self.ivAccountSort,self.ivNameSort, self.ivAddressSort, self.ivCitySort, self.ivZipSort, self.ivLastCallSort, self.ivMileageSort, nil];
//get the image for the button selected
if (buttonTouched.tag == 0) {
strFieldToSort = #"customerNumber";
ivSortImage = self.ivAccountSort;
} else if (buttonTouched.tag == 1) {
strFieldToSort = #"customerName";
ivSortImage = self.ivNameSort;
} else if (buttonTouched.tag == 2) {
strFieldToSort = #"address";
ivSortImage = self.ivAddressSort;
} else if (buttonTouched.tag == 3) {
strFieldToSort = #"city";
ivSortImage = self.ivCitySort;
} else if (buttonTouched.tag == 4) {
strFieldToSort = #"zip";
ivSortImage = self.ivZipSort;
} else if (buttonTouched.tag == 5) {
strFieldToSort = #"lastCallDate";
ivSortImage = self.ivLastCallSort;
} else if (buttonTouched.tag == 6) {
strFieldToSort = #"mileage";
ivSortImage = self.ivMileageSort;
}
//set the sort option and add icon
if (!self.currentSortingOption) {
self.currentSortingOption = SORT_ASC;
[ivSortImage setImage:[UIImage imageNamed:Ascending_Icon]];
} else {
if (![self.btnLastTouched isEqual:buttonTouched]) {
self.currentSortingOption = SORT_ASC;
[ivSortImage setImage:[UIImage imageNamed:Ascending_Icon]];
} else {
if (self.currentSortingOption == SORT_ASC) {
self.currentSortingOption = SORT_DESC;
[ivSortImage setImage:[UIImage imageNamed:Descending_Icon]];
} else {
self.currentSortingOption = SORT_ASC;
[ivSortImage setImage:[UIImage imageNamed:Ascending_Icon]];
}
}
}
//show and hide
for(int i=0; i<arrSortIcons.count; i++) {
UIImageView* ivThisImage = [arrSortIcons objectAtIndex:i];
if (buttonTouched.tag == i) {
[UIView animateWithDuration:.25 animations:^(void) {
ivThisImage.alpha = 1.0;
}];
} else {
[UIView animateWithDuration:.25 animations:^(void) {
ivThisImage.alpha = 0.0;
}];
}
}
//call back to routing view controller and sort results based on sort order and field selected
NSDictionary* dictUserData = [[NSDictionary alloc] initWithObjectsAndKeys:
#"Sort Non-ATI", #"Action",
strFieldToSort, #"Field To Sort",
[NSNumber numberWithLong:self.currentSortingOption], #"Sortng Option",
nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"rvc" object:self userInfo:dictUserData];
self.btnLastTouched = buttonTouched;
}
And the notification fires this method:
- (void) sortNonATIResults : (NSDictionary*) dictSortParams {
if (self.arrNonATIResults.count > 0) {
NSString* sortKey = [dictSortParams objectForKey:#"Field To Sort"];
//change the field to sort to match the customerInfo object properties...
NSNumber* numSortType = [dictSortParams objectForKey:#"Sortng Option"];
BOOL isAsc = YES;
if ([numSortType intValue] == 2) {
isAsc = NO;
}
NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:isAsc];
NSArray* arrSortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
NSArray* arrSortedNonATIResults = (NSArray*)[self.arrNonATIResults sortedArrayUsingDescriptors:arrSortDescriptors];
self.arrNonATIResults = [arrSortedNonATIResults mutableCopy];
self.arrDatasource = self.arrNonATIResults;
[self.accountTable reloadData];
}
}
There are two problems right now. The icons are not showing up if the notification is sent. Comment out the notification and they function as expected. The other problem is that the property currentSortingOption doesn't retain it's value. I think both issues are related but I am not 100% sure. When the tableview is reloaded, does the header get instantiated again? This would make sense to me since then the uiimageviews would be reset with no image and the property would lose it's value and reset to 0 (it is the value of a typedef).
So, I am correct, how can I resolve this and if not, what could be causing the problems?
Thanks
OK, sorry for posting and then solving my problem right away, I guess sometimes you just need to write out the problem to find the solution. All I needed to do was not reload the table but just reload the rows. Here's the updated method:
(void) sortNonATIResults : (NSDictionary*) dictSortParams {
if (self.arrNonATIResults.count > 0) {
NSString* sortKey = [dictSortParams objectForKey:#"Field To Sort"];
//change the field to sort to match the customerInfo object properties...
NSNumber* numSortType = [dictSortParams objectForKey:#"Sortng Option"];
BOOL isAsc = YES;
if ([numSortType intValue] == 2) {
isAsc = NO;
}
NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:isAsc];
NSArray* arrSortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
NSArray* arrSortedNonATIResults = (NSArray*)[self.arrNonATIResults sortedArrayUsingDescriptors:arrSortDescriptors];
self.arrNonATIResults = [arrSortedNonATIResults mutableCopy];
self.arrDatasource = self.arrNonATIResults;
dispatch_async(dispatch_get_main_queue(), ^{
NSMutableArray *indexPathArray = [[NSMutableArray alloc] init];
for (NSInteger section = 0; section < [self.accountTable numberOfSections]; ++section)
{
for (NSInteger row = 0; row < [self.accountTable numberOfRowsInSection:section]; ++row)
{
[indexPathArray addObject:[NSIndexPath indexPathForRow:row inSection:section]];
}
}
[self.accountTable reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationNone];
[self.accountTable scrollsToTop];
});
}
}

dismissViewControllerAnimated does not deallocate viewcontroller

First off: My project is ARC enabled and I'm using storyboard.
I have a view controller that pushes a segue (modal),
[self performSegueWithIdentifier: #"goInitialSettings" sender: self];
there i'm setting some parameters and store them. When the parameters are stored (true a button tap), the app should return to the original viewcontroller.
This i am doing with this command:
[self.presentingViewController dismissViewControllerAnimated:NO completion:^{}];
I'm noticing that the viewcontroller that i dismiss, never deallocs. How does this come?
I'm adding the code of the 'presented viewcontroller' below:
#interface CenterChoiceController ()
{
UIView* _titleBackground;
UILabel* _lblTitle;
UIButton* _btnGaVerder;
UIPickerView* _myPickerView;
NSArray* _centers;
UILabel* _adresLine;
UILabel* _cityLine;
MKPointAnnotation* _point;
MKMapView* _mapView;
UIActivityIndicatorView* _indicator;
UIAlertView* _alert;
GCenter* _center;
DataManager* _dm;
}
#end
#implementation CenterChoiceController
-(void)dealloc
{
NSLog(#"Centerchoice deallocs");
_titleBackground = nil;
_lblTitle = nil;
_btnGaVerder = nil;
_myPickerView = nil;
_point = nil;
_mapView = nil;
_indicator = nil;
_alert = nil;
_centers = nil;
_adresLine = nil;
_cityLine = nil;
_center = nil;
_dm = nil;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_dm = [[DataManager alloc]init];
if([_dm hasConnectivity])
{
[_dm fetchCentersForController:self];
}
else
{
[self pushErrorMessage:NSLocalizedString(#"nointernetconnection", nil)];
}
CAGradientLayer *bgLayer = [BackgroundLayer blueGradient];
bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:bgLayer atIndex:0];
_titleBackground = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
_titleBackground.backgroundColor = [GColor blueColor];
[self.view addSubview:_titleBackground];
_lblTitle = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width - 10, 44)];
_lblTitle.textAlignment = NSTextAlignmentRight;
_lblTitle.textColor = [GColor whiteColor];
_lblTitle.text = NSLocalizedString(#"bioscoopkeuze", nil);
[self.view addSubview:_lblTitle];
_btnGaVerder = [[UIButton alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height - 54, self.view.frame.size.width, 54)];
[_btnGaVerder setTitle:NSLocalizedString(#"gaverder", nil) forState:UIControlStateNormal];
_btnGaVerder.titleLabel.font = [_btnGaVerder.titleLabel.font fontWithSize:12];
_btnGaVerder.backgroundColor = [GColor blueColor];
[_btnGaVerder setTitleColor:[GColor whiteColor] forState:UIControlStateNormal];
[_btnGaVerder setShowsTouchWhenHighlighted:YES];
[_btnGaVerder addTarget:self action:#selector(gaVerder) forControlEvents:UIControlEventTouchUpInside];
_myPickerView = [[UIPickerView alloc]initWithFrame:CGRectMake(0, 44, self.view.frame.size.width, 200)];
}
-(void)showLoading
{
NSLog(#"shows loading");
_indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
CGPoint cntr = self.view.center;
_indicator.center = cntr;
[_indicator startAnimating];
[self.view addSubview:_indicator];
}
-(void)hideLoading
{
NSLog(#"hides loading");
[_indicator removeFromSuperview];
_indicator = nil;
}
-(void)pushData:(NSArray *)data
{
[self.view addSubview:_btnGaVerder];
[self.view addSubview:_myPickerView];
_centers = data;
_myPickerView.delegate = self;
_myPickerView.dataSource = self;
_dm = [[DataManager alloc]init];
GSettings* settings = [_dm loadSettings];
if(settings == nil)
{
settings = [[GSettings alloc]init];
settings.chosenCenter = [_centers objectAtIndex:0];
settings.loadedCenter = [_centers objectAtIndex:0];
_center = settings.chosenCenter;
settings.notificationsEnabled = YES;
[self changeAddressLines];
}
/*if(settings != nil)
{
GCenter* loaded = settings.loadedCenter;
int i = 0;
BOOL found = NO;
while(i < [_centers count] && !found)
{
GCenter* center = (GCenter*)[_centers objectAtIndex:i];
if(settings.loadedCenter.iD == center.iD)
{
_center = center;
settings.chosenCenter = center;
[_dm storeSettings:settings];
found = YES;
}
i++;
}
//[self.myPickerView selectRow:i-1 inComponent:0 animated:NO];
loaded = nil;
[self changeAddressLines];
}
*/
}
-(void) pushErrorMessage: (NSString*) errorMessage
{
_alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"fout", nil) message:errorMessage delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
_alert.delegate = self;
[_alert show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == 0)
{
if(self.navigationController != nil)
{
[self.navigationController popViewControllerAnimated:YES];
}
else
{
//[self initializeData];
}
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewWillDisappear:(BOOL)animated
{
[_dm cancelCenterRequest];
/*if(self.tabBarController != nil)
{
dm = [[DataManager alloc]init];
settings = [dm loadSettings];
if([dm hasConnectivity])
{
settings.lastUpdated = nil;
[dm storeSettings:settings];
}
if(settings.loadedCenter.centerCode != settings.chosenCenter.centerCode)
{
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SplashScreenController *controller = [mystoryboard instantiateViewControllerWithIdentifier:#"root"];
[self presentViewController:controller animated:YES completion:nil];
}
dm = nil;
settings = nil;
}
*/
}
-(void)gaVerder
{
_dm = [[DataManager alloc]init];
GSettings* settings = [_dm loadSettings];
if(settings == nil)
{
settings = [[GSettings alloc]init];
settings.notificationsEnabled = YES;
}
if(_center != nil)
{
settings.chosenCenter = _center;
}
[_dm storeSettings:settings];
[_mapView removeFromSuperview];
_mapView = nil;
_titleBackground = nil;
_lblTitle = nil;
_btnGaVerder = nil;
_myPickerView = nil;
_point = nil;
_indicator = nil;
_alert = nil;
_centers = nil;
_adresLine = nil;
_cityLine = nil;
_center = nil;
_dm = nil;
[self.presentingViewController dismissViewControllerAnimated:NO completion:^{}];
//DEZE BLIJFT HELAAS IN HET GEHEUGEN HANGEN... GEEN OPLOSSING GEVONDEN
//[self.navigationController popViewControllerAnimated:NO];
}
//PICKERVIEWDELEGATE EN DATASOURCE
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [_centers count];
}
- (UILabel *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
GCenter* center = (GCenter*)[_centers objectAtIndex:row];
NSString* string = center.name;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, pickerView.frame.size.width, 44)];
label.textColor = [GColor blueColor];
label.font = [label.font fontWithSize:18];
label.text = string;
label.textAlignment = NSTextAlignmentCenter;
return label;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
_center = (GCenter*)[_centers objectAtIndex:row];
[self changeAddressLines];
}
-(void)changeAddressLines
{
if (_mapView != nil)
{
[_mapView removeAnnotation:_point];
}
[_adresLine removeFromSuperview];
[_cityLine removeFromSuperview];
_adresLine = nil;
_cityLine = nil;
CGRect rctAdres = CGRectMake(0, _myPickerView.frame.origin.y + _myPickerView.frame.size.height -10, self.view.frame.size.width, 20);
_adresLine = [[UILabel alloc]initWithFrame:rctAdres];
_adresLine.textAlignment = NSTextAlignmentCenter;
_adresLine.textColor = [GColor greyColor];
_adresLine.text = _center.street;
CGRect rctCity = CGRectMake(0, rctAdres.origin.y + rctAdres.size.height, self.view.frame.size.width, 20);
_cityLine = [[UILabel alloc]initWithFrame:rctCity];
_cityLine.textAlignment = NSTextAlignmentCenter;
_cityLine.textColor = [GColor greyColor];
_cityLine.font = [_cityLine.font fontWithSize:14];
_cityLine.text = _center.city;
[self.view addSubview:_adresLine];
[self.view addSubview:_cityLine];
if(_mapView == nil)
{
double height;
height = _btnGaVerder.frame.origin.y - _cityLine.frame.origin.y - _cityLine.frame.size.height;
CGRect mapRect = CGRectMake(0, _cityLine.frame.origin.y+3 + _cityLine.frame.size.height, self.view.frame.size.width, height);
_mapView = [[MKMapView alloc]initWithFrame:mapRect];
[self.view addSubview:_mapView];
}
CLLocationCoordinate2D punt;
punt.latitude = _center.latitude;
punt.longitude = _center.longitude;
_point = [[MKPointAnnotation alloc] init];
[_point setCoordinate:punt];
_mapView.centerCoordinate = punt;
_point.title = _center.name;
[_mapView addAnnotation:_point];
[_mapView setCenterCoordinate:punt animated:YES];
MKCoordinateRegion theRegion = _mapView.region;
theRegion.span.longitudeDelta = 0.005;
theRegion.span.latitudeDelta = 0.005;
[_mapView setRegion:theRegion animated:YES];
}
#end
In my case it was a little more complicated. I don't have any variable that has strong reference to my view controller, and my view controller is not a strong delegate to any property/variable contained inside this class itself. After some hard thinking and trials, I found my issue was caused by a NSTimer object defined in the interface. The timer object itself is non-repeatable, but the method invoked by it will schedule the timer again at the end, which as you can imagine would reference this method defined in my view controller again, thus causing circular references. To break out of this loop, I had to invalidate the timer before I dismiss my view controller.
As a summary, these are cases when a view controller can be blocked from deallocating after it is dismissed:
The view controller is being strongly referenced by some outside object;
The view controller is a strong delegate referenced by some object defined within the view controller itself
The dismissViewControllerAnimated:completion: block may reference to self or it has some other code block that may cause a circular references
The view controller has NSTimer objects which can invoke some methods which re-schedules the timer
There could be more, but hopefully we can capture a lot of cases with the above cases.
If your view controller is not deallocated after it is dismissed, there's probably a strong reference to that view controller somewhere in your code. ARC will always deallocate objects that doesn't have strong reference anymore.

three dependent picker view

I need to create three independent pickerView's. The first pickerView is categoryPickerView. When a value is selected it should load other 2 pickerView's (productPickerview and modelPickerview) are not loading the data correctly.
The didSelectRow callback is being fired but my NSLog's have shown that its not getting passed the first if statement checking if its equal to "Audio"
For catogeryPickerView I have written following array for it in viewDidLoad:-
devicecatogery=[[NSArray alloc]initWithObjects:#"Audio",#"Video", nil];
//code for numeric keypad done button
UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 44, 320, 300)];
numberToolbar.barStyle = UIBarStyleBlackTranslucent;
numberToolbar.items = [NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancelNumberPad)],
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Apply" style:UIBarButtonItemStyleDone target:self action:#selector(doneWithNumberPad)],
nil];
[numberToolbar sizeToFit];
// catogery pickerview
categoryPickerView=[[UIPickerView alloc]init];
categoryPickerView.delegate=self;
categoryPickerView.tag=1;
txtCategory.inputView=categoryPickerView;
txtCategory.inputAccessoryView=numberToolbar;
//product pickerview
productPickerView=[[UIPickerView alloc]init];
productPickerView.delegate=self;
productPickerView.tag=2;
txtProduct.inputView=productPickerView;
txtProduct.inputAccessoryView=numberToolbar;
//model pickerview
modelPickerView=[[UIPickerView alloc]init];
modelPickerView.delegate=self;
modelPickerView.tag=3;
txtModel.inputView=modelPickerView;
txtModel.inputAccessoryView=numberToolbar;
}//end of view did load
this is my event for picker view:-
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
if (pickerView.tag == 1) {
return [devicecatogery count]; //<-----------this is for category picker view
}else if(pickerView.tag == 2)
return [commanProductArray count]; //<-----------this is for product picker view
else
return [commanModelArray count]; //<-------------- this is for model picker view
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if (pickerView.tag == 1)
return [devicecatogery objectAtIndex:row];//<----this is for category picker view
else if (pickerView.tag == 2)
return [commanProductArray objectAtIndex:row];//<--------this is for product picker view
else
return [commanModelArray objectAtIndex:row];//<--------- this is for model picker view
}
Here is my didSelect callback:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if ([[categoryArray objectAtIndex:[categoryPickerView selectedRowInComponent:0] ] isEqual:#"Audio"]) {
commanProductArray=[[NSMutableArray alloc]initWithObjects:#"walkman",#"mp3",#"ipod", nil];
if ([[commanProductArray objectAtIndex:[productPickerView selectedRowInComponent:0]] isEqual:#"walkman"]) {
// walkman list display
[productPickerView reloadAllComponents];
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"walkman1",#"walkman2",#"walkman3",#"walkman4", nil];
[modelPickerView reloadAllComponents];
}else if ([[commanProductArray objectAtIndex:[productPickerView selectedRowInComponent:0]] isEqual:#"mp3"]){
//mp3 list display
[productPickerView reloadAllComponents];
[modelPickerView reloadAllComponents];
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"mp3",#"mp3",#"mp3",#"mp3", nil];
}else if ([[commanProductArray objectAtIndex:[productPickerView selectedRowInComponent:0]] isEqual:#"ipod"]){
//ipod list display
[productPickerView reloadAllComponents];
[modelPickerView reloadAllComponents];
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"ipod1",#"ipod2",#"ipod3",#"ipod4", nil];
}
}else if ([[categoryArray objectAtIndex:[categoryPickerView selectedRowInComponent:0]] isEqual:#"Video"]){
commanProductArray=[[NSMutableArray alloc]initWithObjects:#"TV",#"Moniter",#"Projector", nil];
if ([[commanProductArray objectAtIndex:[productPickerView selectedRowInComponent:0]]isEqual:#"TV"]) {
//for tv model display
[productPickerView reloadAllComponents];
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"TV1",#"TV2",#"TV3", nil];
[modelPickerView reloadAllComponents];
}else if ([[commanProductArray objectAtIndex:[productPickerView selectedRowInComponent:0]]isEqual:#"Moniter"]){
//for moniter model display
[productPickerView reloadAllComponents];
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"Moniter1",#"Moniter2",#"Moniter3", nil];
[modelPickerView reloadAllComponents];
}else if ([[commanProductArray objectAtIndex:[productPickerView selectedRowInComponent:0]] isEqual:#"Projector"]){
//for projector display
[productPickerView reloadAllComponents];
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"Projector1",#"Projector2",#"Projector3", nil];
[modelPickerView reloadAllComponents];
}
}
}
This code doesn't make sense to me, I suspect your issue is here:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if ([[categoryArray objectAtIndex:[categoryPickerView selectedRowInComponent:0] ] isEqual:#"Audio"]) {
commanProductArray=[[NSMutableArray alloc]initWithObjects:#"walkman",#"mp3",#"ipod", nil];
if ([[commanProductArray objectAtIndex:[productPickerView selectedRowInComponent:0]] isEqual:#"walkman"]) {
// walkman list display
[productPickerView reloadAllComponents];
All of the pickerView's are going into this callback when selected. You are first of all not checking the tags to see which pickerView it was that fired, then you check if the row selected is audio / video, if its the second / third pickers, the code will never get passed this as they will not have audio / video selected.
Following the logic, if "Audio" is selected you set commanProductArray to the given values, then you immediately check the selected value is equal to "walkman" before loading it.
[productPickerView reloadAllComponents]; should be called directly after commanProductArray is set I suspect, as you set the array and check which value is selected before loading it.
This issue could have been spotted by simply putting 2 or 3 NSlog's to see was it getting into the loop
EDIT:
Your code should follow something more like this:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// If first picker
if(pickerView.tag == 1)
{
// If Audio
if(row == 0)
{
// Load result for audio
}
// If Video
else if (row == 1)
{
// load result for video
}
}
// If second picker
else if(pickerView.tag == 2)
{
// if Walkman
if(row == 0)
{
// load result for walkman
}
// etc etc etc
}
else if (pickerView.tag == 3)
{
}
}
Try this one:
- (void)viewDidLoad
{
devicecatogery=[[NSArray alloc]initWithObjects:#"Audio",#"Video", nil];
commanProductArray=[[NSMutableArray alloc]initWithObjects:#"walkman",#"mp3",#"ipod", nil];
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"walkman1",#"walkman2",#"walkman3",#"walkman4", nil];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
// tell the picker how many rows are available for a given component
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (pickerView.tag==1) {
return devicecatogery.count;
}
else if(pickerView.tag==2){
return commanProductArray.count;
}
else if (pickerView.tag==3)
{
return commanModelArray.count;
}
return 0;
}
// tell the picker how many components it will have
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
// tell the picker the title for a given component
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *title;
if (pickerView.tag==1)
{
title = [NSString stringWithFormat:#"%#",[devicecatogery objectAtIndex:row]];
}
else if (pickerView.tag==2)
{
if([categoryPickerView selectedRowInComponent:0]==0)
{
commanProductArray=[[NSMutableArray alloc]initWithObjects:#"walkman",#"mp3",#"ipod", nil];
}
else{
commanProductArray=[[NSMutableArray alloc]initWithObjects:#"TV",#"Moniter",#"Projector", nil];
}
title = [NSString stringWithFormat:#"%#",[commanProductArray objectAtIndex:row]];
}
else if (pickerView.tag==3)
{
if ([[devicecatogery objectAtIndex:[categoryPickerView selectedRowInComponent:0]] isEqualToString:#"Audio"]) {
if([productPickerview selectedRowInComponent:0]==0)
{
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"walkman1",#"walkman2",#"walkman3",#"walkman4", nil];
}
else if([productPickerview selectedRowInComponent:0]==1)
{
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"mp31",#"mp32",#"mp33",#"mp34", nil];
}
else if([productPickerview selectedRowInComponent:0]==2)
{
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"ipod1",#"ipod2",#"ipod3",#"ipod4", nil];
}
}
else
{
if([productPickerview selectedRowInComponent:0]==0)
{
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"TV1",#"TV2",#"TV3",#"TV4", nil];
}
else if([productPickerview selectedRowInComponent:0]==1)
{
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"Moniter1",#"Moniter2",#"Moniter3",#"Moniter4", nil];
}
else if([productPickerview selectedRowInComponent:0]==2)
{
commanModelArray=[[NSMutableArray alloc]initWithObjects:#"Projector1",#"Projector2",#"Projector3",#"Projector4", nil];
}
}
title = [NSString stringWithFormat:#"%#",[commanModelArray objectAtIndex:row]];
}
return title;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if (pickerView.tag==1)
{
[productPickerview reloadAllComponents];
[modelPickerview reloadAllComponents];
}
if (pickerView.tag==2) {
[modelPickerview reloadAllComponents];
}
// Handle the selection
}
For more detail you have to check it : Sample code
May it will help you.
Happy coding...:)

Custom UIPickerView crashes when datasource does not have data

I have a screen with two text fields (category, subcategory), each hooked up to a custom UIPickerView. The options present in the subcategory view depend on the category selected as the value of the first field.
If the user has not selected a category, selecting the subcategory field brings up the standard keyboard (this behavior is fine).
If the user selects a category and then interacts with the subcategory field everything works fine.
The problem happens when the user puts in a category, brings up the subcategory picker, and then goes back and clears the category field. At this point, if the user selects the subcategory field, the picker will appear without any data and interacting with it will cause the app to crash.
The error text:
*** Assertion failure in -[UITableViewRowData rectForRow:inSection:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableViewRowData.m:1630
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'request for rect at invalid index path (<NSIndexPath 0x719eb60> 2 indexes [0, 0])'
*** First throw call stack:
(0x1cc3012 0x1100e7e 0x1cc2e78 0xb96665 0x22df20 0xf12de 0x481086 0x480f7a 0xa440d 0xa69eb 0x30f85a 0x30e99b 0x3100df 0x312d2d 0x312cac 0x30aa28 0x77972 0x77e53 0x55d4a 0x47698 0x1c1edf9 0x1c1ead0 0x1c38bf5 0x1c38962 0x1c69bb6 0x1c68f44 0x1c68e1b 0x1c1d7e3 0x1c1d668 0x44ffc 0x2acd 0x29f5)
libc++abi.dylib: terminate called throwing an exception
Here is my code:
- (IBAction)showYourPicker:(id)sender {
isCategoryPicker = true;
// create a UIPicker view as a custom keyboard view
UIPickerView* pickerView = [[UIPickerView alloc] init];
[pickerView sizeToFit];
pickerView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
pickerView.delegate = self;
pickerView.dataSource = self;
pickerView.showsSelectionIndicator = YES;
self.catPickView = pickerView; //UIPickerView
categoryField.inputView = pickerView;
// create a done view + done button, attach to it a doneClicked action, and place it in a toolbar as an accessory input view...
// Prepare done button
UIToolbar* keyboardDoneButtonView = [[UIToolbar alloc] init];
keyboardDoneButtonView.barStyle = UIBarStyleBlack;
keyboardDoneButtonView.translucent = YES;
keyboardDoneButtonView.tintColor = nil;
[keyboardDoneButtonView sizeToFit];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered target:self
action:#selector(pickerDoneClicked:)];
[keyboardDoneButtonView setItems:[NSArray arrayWithObjects:doneButton, nil]];
// Plug the keyboardDoneButtonView into the text field...
categoryField.inputAccessoryView = keyboardDoneButtonView;
}
- (IBAction)showYourSubPicker:(id)sender {
isCategoryPicker = false;
WCSharedCache *sharedManager = [WCSharedCache sharedManager];
BOOL iLLAllowIt = false;
for(int i = 0; i < [sharedManager.categories count]; i++) {
if([[[sharedManager categories] objectAtIndex:i] isEqualToString:[categoryField text]]) {
iLLAllowIt = true;
}
}
if(!iLLAllowIt) {
return;
}
// create a UIPicker view as a custom keyboard view
UIPickerView* pickerView = [[UIPickerView alloc] init];
[pickerView sizeToFit];
pickerView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
pickerView.delegate = self;
pickerView.dataSource = self;
pickerView.showsSelectionIndicator = YES;
self.subCatPickView = pickerView; //UIPickerView
subcategoryField.inputView = pickerView;
// create a done view + done button, attach to it a doneClicked action, and place it in a toolbar as an accessory input view...
// Prepare done button
UIToolbar* keyboardDoneButtonView = [[UIToolbar alloc] init];
keyboardDoneButtonView.barStyle = UIBarStyleBlack;
keyboardDoneButtonView.translucent = YES;
keyboardDoneButtonView.tintColor = nil;
[keyboardDoneButtonView sizeToFit];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered target:self
action:#selector(pickerDoneClicked:)];
[keyboardDoneButtonView setItems:[NSArray arrayWithObjects:doneButton, nil]];
// Plug the keyboardDoneButtonView into the text field...
subcategoryField.inputAccessoryView = keyboardDoneButtonView;
}
- (void) pickerDoneClicked: (id) picker {
if(isCategoryPicker) {
[categoryField resignFirstResponder];
} else {
[subcategoryField resignFirstResponder];
}
}
- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
WCSharedCache *sharedManager = [WCSharedCache sharedManager];
if(isCategoryPicker) {
[categoryField setText:[[sharedManager categories] objectAtIndex:row]];
} else {
#try {
int idx = 0;
for(int i = 0; i < [sharedManager.categories count]; i++) {
if([[[sharedManager categories] objectAtIndex:i] isEqualToString:[categoryField text]]) {
idx = i;
break;
}
}
[subcategoryField setText:[[[sharedManager subcategories]objectAtIndex:idx] objectAtIndex:row]];
} #catch (NSException *e) {
NSLog(#"Exception: %#",e);
[subcategoryField setText:#"" ];
}
}
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
WCSharedCache *sharedManager = [WCSharedCache sharedManager];
if(isCategoryPicker) {
return [[sharedManager categories]count];
} else {
for(int i = 0; i < [sharedManager.categories count]; i++) {
if([[[sharedManager categories] objectAtIndex:i] isEqualToString:[categoryField text]]) {
return [[[sharedManager subcategories] objectAtIndex:i] count];
}
}
}
return 0;
}
- (NSString *)pickerView: (UIPickerView *)pickerView titleForRow: (NSInteger)row forComponent:(NSInteger)component
{
WCSharedCache *sharedManager = [WCSharedCache sharedManager];
if(isCategoryPicker) {
return [[sharedManager categories] objectAtIndex:row];
} else {
for(int i = 0; i < [sharedManager.categories count]; i++) {
if([[[sharedManager categories] objectAtIndex:i] isEqualToString:[categoryField text]]) {
return [[[sharedManager subcategories] objectAtIndex:i] objectAtIndex:row];
}
}
}
return #"";
}
Is there a method I can implement, or a try-catch, or revival of original keyboard, or somewhere I can prevent the user from hitting this field if there is no data any of those would work. The data for categories is in an NSArray. The data for subcategories is in a two-dimensional NSArray indexed off of the index of the associated category.
If fixed this problem by changing the default value in:
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
WCSharedCache *sharedManager = [WCSharedCache sharedManager];
if(isCategoryPicker) {
return [[sharedManager categories]count];
} else {
for(int i = 0; i < [sharedManager.categories count]; i++) {
if([[[sharedManager categories] objectAtIndex:i] isEqualToString:[categoryField text]]) {
return [[[sharedManager subcategories] objectAtIndex:i] count];
}
}
}
return 1;
}
from zero to one. Apparently, UIPickerView (at least in the implementation above) cannot handle scrolling without throwing an exception if the number of rows in the component is 0. This is curious, because according the Apple's documentation of the UIPickerView class, the default value for this method is 0.

Resources