I'm trying to build an app which works alongside a database of PDF's. What I need is for the app to look at all of the files (PDF's) which are stored and to pull the certain files out, check this against the database and then show a list of which PDF's are available on a UIPicker.
My first step would be that the app checks the files and creates a picker wheel which has been populated with the countries for which there is data in the directory.
To make this work I have created a standard format for the file names: 'Country-Airfield-Plate Name-Date.pdf', e.g. “UK-London Heathrow-ILS DME NDB 27-100214.pdf”. I've split this filename first at the full stop to get two strings: 'UK-London Heathrow-ILS DME NDB 27’ and ‘pdf’, and then we split the title at the hyphens to get ‘UK’, ‘London Heathrow’ and ‘ILS DME NDB 27’.
The app will check the first string for the country information, then the second for the airfield and will then display a list of the third strings for the appropriate airfield.
How can I First Fetch the data from database for a particular field for eg. country make a NSArray form that data and load that NSArray to UIPickerView, then use that array in UIPickerView Delegate and Datasource methods?
If you don't have any web service going and you are handling the documents yourself. You can hardcode a .plist file and put it on your website, download this small plist file every time the app opens, encrypt and save it to your documents directory.
The plist is basically a NSDictionary with objects and keys.
So your plist structure would look like this:
{
Countries = (
{
Airfields = (
{
Code = JNB;
Plates = (
{
Title = "Plate 1";
URL = "http://www.airport.com/za/airfield/plate1/document.pdf";
}
);
Title = "OR Tambo";
}
);
Title = "South Africa";
}
);
}
The above example only holds 1 object in each array in your case it would be more.
Then use the following UIPickerView delegate assuming button.tag is called to change pickerview.tag and display correct array for the pickerview:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
{
return [[self returnCorrectArrayForButton:pickerView.tag] count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [[[self returnCorrectArrayForButton:pickerView.tag] objectAtIndex:row] valueForKey:#"Title"];
}
// Handle these errors where user can click on any button. Airfields will be empty if no country selected. Plates will be empty when no Airfields selected. After loading all arrays, pressing random buttons might give wrong information.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if (pickerView.tag == 1) {
_airfieldArray = [[_countryArray objectAtIndex:row] objectForKey:#"Airfields"];
[_countryButton setTitle:[[_countryArray objectAtIndex:row] valueForKey:#"Title"] forState:UIControlStateNormal];
} else if (pickerView.tag == 2) {
_plateArray = [[_airfieldArray objectAtIndex:row] objectForKey:#"Plates"];
[_airfieldButton setTitle:[[_airfieldArray objectAtIndex:row] valueForKey:#"Title"] forState:UIControlStateNormal];
} else if (pickerView.tag == 3) {
// Show PDF in webview for selected plate
[_plateButton setTitle:[[_plateArray objectAtIndex:row] valueForKey:#"Title"] forState:UIControlStateNormal];
NSString *urlString = [[_plateArray objectAtIndex:row] valueForKey:#"URL"];
NSLog(#"Selected Plate PDF URL : %#", urlString);
}
}
- (NSArray *)returnCorrectArrayForButton:(NSUInteger)buttonIndex
{
if (buttonIndex == 1) {
// Return Countries array
return _countryArray;
} else if (buttonIndex == 2) {
// Return Airfield array
return _airfieldArray;
} else if (buttonIndex == 3) {
// Return Plates array
return _plateArray;
}
return nil;
}
Related
I am creating simple reveal menu in my demo application. Right now what I am doing is I have a one MutableArray named MutableMenu
NSArray menu = [#"menu1",#"Menu2","Menu3",#"Menu4"];
MutableMenu = [NSMutableArray alloc]initwithArray:menu];
I am just displaying this mutable array in my by default tableview cell.
In cellForRowAtIndexPath method I am using static indexing like below code snippet
if(indexPath.row == 0){
[self performSegueWithIdentifier:SEGUE_TO_MANAGE_TASK sender:nil];
}
if(indexPath.row == 1){
[self performSegueWithIdentifier:SEGUE_TO_MANAGE_LEAVE sender:nil];
}
All is working great till now. Now I have a array that I want to check permission to display in tableview cell. For example first user have only 2 permissions from 4 menus. This user only able to access menu1 and menu2. Likewise different users different permissions.
This is my code to maintaining this scenario in viewDidLoad. All is working fine
BOOL permisson = NO;
NSArray *Roles = [USERDEFAULT objectForKey:PREF_ROLE_ARRAY];
for (NSString *temp in Roles) {
if ([temp isEqualToString:#"55"] || [temp isEqualToString:#"45"] || [temp isEqualToString:#"67"] ) {
permisson = YES;
if ([Mutablemenu containsObject:#"Team management"])
NSLog(#"Already Have");
else [Mutablemenu insertObject:#"Team management" atIndex:2];
}
}
if (!permisson) {
[Mutablemenu removeObject:#"Team management"];
[Mutablemenu insertObject:#"" atIndex:2];
[MutableImages removeObject:#"team.png"];
}
[_tableview reloadData];
All is working fine But when user have only 3 permission.My indexing is changed in didSelectRowatIndexPath. For Example first user have 4 permission then index is 0,1,2,3 but when user have 3 permission then index is 0,1,2.
But my question is how do I handle this situation in didSelectRowatIndexPath. Because every time indexing is changed.
As told by #RJV Kumar, you should have check actual menu clicked instead of indexPath in didSelectRowatIndexPath as:
if([menuArray[indexPath.row] isEqualToString: #"Menu1"]){
[self performSegueWithIdentifier:SEGUE_TO_HANDLE_MENU_1 sender:nil];
}
else if([menuArray[indexPath.row] isEqualToString: #"Menu2"]){
[self performSegueWithIdentifier:SEGUE_TO_HANDLE_MENU_2 sender:nil];
}
.
.
so on...
As per my understanding, you are finding the menu based on index, but you should not do like that,
instead of that maintain menuid or menuname to identify which menu the user selected. By this way, you don't have to worry about the index.
In didselectRow method, by comparing menuid or menuname, do your operation
I have a UIPickerView, and it is showing up, but it just shows (null). Why is this? I have it conformed to the delegate's I need in.
EDIT: more detail.
Basically, my app is a flight logbook. You make planes, which you saves, and you can pick it when you make a new session. The planeNum key stores how many planes there are, and the key Plane%liTailNumber has the tail number for that plane.
This is my code:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return (long)[[NSUserDefaults standardUserDefaults]integerForKey:#"planeNum"];
}
NSMutableArray *tailPickerOptions;
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
NSInteger num = [[NSUserDefaults standardUserDefaults]integerForKey:#"planeNum"];
while (num > 0){
--num;
tailPickerOptions = [[NSMutableArray alloc]init];
NSString *dTailNumber = [NSString stringWithFormat:#"%#", [[NSUserDefaults standardUserDefaults]objectForKey:[NSString stringWithFormat:#"Plane%liTailNumber", (long)num]]];
[tailPickerOptions addObject:dTailNumber];
NSLog(#"%#", tailPickerOptions);
}
return tailPickerOptions[row];
}
You initialize a new array for each loop of the while. Your code also doesn't ensure you actually initialize the array - if num = 0, you'll never go in and declare the array. There should be a warning or compiler error for this. In the best case scenario because you keep declaring a new array in your loop, you'll return a max of 1 element ever.
Move your array declaration above the while loop.
So i have a switch and when it is "on" i would like the CPPickerView to switch to a particular value in an array. As well if the pickerview is moved again i would like the switch to move to the off position.
I know how to get the current day of the week and am trying to switch the pickerview selection to the current day of the week.
If i am way off base here asking such a generalised question just let me know or if you need any more information.
//CPPicker
self.daysOfWeekData = [[NSArray alloc] initWithObjects:#"Monday", #"Tuesday", #"Wednesday", #"Thursday", #"Friday", #"Saturday", #"Sunday", nil];
self.dayPickerView.allowSlowDeceleration = YES;
[self.dayPickerView reloadData];
#pragma mark - Horizontal pickerview
//DataSource
-(NSInteger)numberOfItemsInPickerView:(CPPickerView *)pickerView {
return 7;
}
-(NSString *)pickerView:(CPPickerView *)pickerView titleForItem:(NSInteger)item {
return daysOfWeekData[item];
}
//Delegate
-(void)pickerView:(CPPickerView *)pickerView didSelectItem:(NSInteger)item {
self.dayLabel.text = [NSString stringWithFormat:#"%#", daysOfWeekData[item]];
}
//Today's day date
- (IBAction)todaySwitchChange:(id)sender {
if (todaySwitch.on) {
NSLog(#"It is on");
} else {
NSLog(#"It is off");
}
}
This can be done by using CPPickerView's setSelectedItem:animated: method, along with the normal delegate methods.
In your todaySwitchChange: method when the switch is turned on, set the CPPickerView to your desired index:
//Today's day date
- (IBAction)todaySwitchChange:(id)sender {
if (todaySwitch.on) {
NSLog(#"It is on");
// This will cause the CPPickerView to select the item you choose
NSUInteger itemToSelect = someValue; //whatever logic you need to select the right index
[self.dayPickerView setSelectedItem:itemToSelect animated:YES]; // Or disable animation if desired
} else {
NSLog(#"It is off");
}
}
To toggle the switch off when the user scrolls on the CPPickerView, you'll need to hook into the delegate method which gives you notification that scrolling has occurred:
// Implement the following delegate method
- (void)pickerViewWillBeginChangingItem:(CPPickerView *)pickerView {
// Picker is going to change due to user scrolling, so turn the switch off
if (todaySwitch.on) {
todaySwitch.on = NO;
}
}
Hope this helps!
I am working on a small converter app for my school project, an app that won't be published in App Store, just for school grade. I am wondering if anyone knows how did this developer in this app
made connections for converting values? The simplest way i can imagine is with switch cases but that would make too much unnecessary code:
if (first column is distance) then if(second column is metres)
case0:third column is yards -> do something
case1:third column is kilometers ->do something
case2:third column is metros ->do nothing
etc....
Thanks for answering.
EDIT:
Thanks for fast answer, this is what i made so far, iOS simulator is displaying correctly three column picker in which second two are displayed depending on the row of the first one. Can u tell me is this any good? Maybe some things are uneccesary complicated?
#import "konverterViewController.h"
#interface konverterViewController ()
#end
#implementation konverterViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.fizVelicine = [[NSArray alloc] initWithObjects:#"distance",#"mass" , nil];
self.udaljenostJedinice = [[NSArray alloc] initWithObjects:#"meter", #"kilometer", #"yard", #"inch", nil];
self.masaJedinice = [[NSArray alloc] initWithObjects:#"kilogram",#"dekagram",#"gram",#"tone" , nil];
}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel *retval = (id)view;
if (!retval) {
retval = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f,
[pickerView rowSizeForComponent:component].width,
[pickerView rowSizeForComponent:component].height)];
}
retval.opaque = NO;
retval.backgroundColor = [UIColor orangeColor];
retval.adjustsFontSizeToFitWidth = YES;
retval.font = [UIFont systemFontOfSize:12];
if (component == 0) {
retval.textAlignment = NSTextAlignmentCenter;
retval.text = [self.fizVelicine objectAtIndex:row];
}
else if ([self.odabir isEqualToString:#"distance"]){
retval.textAlignment = NSTextAlignmentCenter;
retval.text = [self.udaljenostJedinice objectAtIndex:row];
}
else {
retval.textAlignment = NSTextAlignmentCenter;
retval.text = [self.masaJedinice objectAtIndex:row];
}
return retval;
}
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 3;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent: (NSInteger)component
{
if(component== 0)
{
return [self.fizVelicine count];
}
else
{
if([self.odabir isEqualToString:#"distance"]){ return [self.udaljenostJedinice count];}
else {return [self.masaJedinice count];}
}
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
if(component == 0)
{
return [self.fizVelicine objectAtIndex:row];
}
else {
if([self.odabir isEqualToString:#"distance]){
return [self.udaljenostJedinice objectAtIndex:row];}
else {
return [self.masaJedinice objectAtIndex:row];
}
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if (component == 0) {
self.odabir=[[NSString alloc] initWithFormat:#"%#" , [self.fizVelicine objectAtIndex:row]];
[pickerView reloadAllComponents];}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
It sounds like you're puzzling over how to initialize the picker sections at the top. I think you'll need a data structure that is an array of arrays:
#[#"distance", #[#"meters", #"inches", #"cubits", #"whatevers"],
#"weight", #[#"grams", // etc
Tell the picker that you have three segments. The first segment can be manufactured (and cached, if you want) as the first elements of each sub-array. The second two segments get their values from the data structure, indexed by the value of the first section.
EDIT; You'll probably want a data structure that helps you compute the conversion. For each kind of measure, imagine an NxN table, where N is the number of units on the wheels. A row let's you look up the left wheel setting and the column lets you look up the right wheel. The table should contain what you need to do the calculation. If all of the measures linearly related, like inches-meters, the table can simply contain floats (wrapped as NSNumber) conversion factors.
// conversion factors for distance, units as the first value, conversion factors in a subarray
// meters = 1*meters, 39.37*inches, 2.19*cubits, etc
NSArray *conversions =
#[#"meters", #[#1.0, #39.37, #2.19, //etc
#"inches", // etc. conversions to meters inches cubits etc.
You might notice that this array contains some waste. Only half the table is needed, since inches->meters is just the reciprocal of meters->inches) but I think the space small enough to not worry about this. You might also notice that the table is good only for simple linear relationships between units. Centigrade to Fahrenheit will require a different treatment. The most general treatment for arbitrary conversions might be an array of blocks that carry out the computation. But I suggest starting more simply.
EDIT AGAIN:
Now, to get a conversion formula, get the current picker selections and look up a conversion factor:
NSInteger fromUnitsIndex = [self.picker selectedRowInComponent:1];
NSArray *fromArray = self.conversions[fromUnitsIndex];
// the second member of this array is an array of conversion factors
NSArray *conversionNumbers = fromArray[1];
NSInteger toUnitsIndex = [self.picker selectedRowInComponent:2];
NSNumber *conversionNumber = conversionNumbers[toUnitsIndex];
It sounds like a fun project. Good luck!
For one of my last school projects, I am creating an iPad/iPhone application. For some days now I've been working on an issue with a certain memory leak. My application starts out on a specific view-controller (VCMainStatistics_iPad). From there, I push another view-controller (VCSocialMedia_iPad). Afterwards, I go back to the first view-controller.
When I repeat this sequence, I notice (by using Instruments - Activity Monitor) that the memory usage of the app keeps increasing. By disabling parts of the code, I eventually found out it has something to do with the pickerView. This code gives no leaks:
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return 0;
}
However, when I increase the number of rows, leaks start emerging (roughly 0.07 MB per row). Obviously, this is why I believe the pickerView is the cause of the leaks. I've been trying to remove the subviews from the pickerView before deallocation, setting pickerView to nil, and lots of other things... nothing fixes the issue. To hopefully make things a bit clearer, I'll post some more code.
The header file:
#import "UniversalViewController.h"
#define DATATYPE_SOCIALMEDIA 0
#interface VCSocialMedia_iPad : UniversalViewController <UIPickerViewDataSource, UIPickerViewDelegate>
{
NSArray *lMediaTypes;
NSMutableArray *lMediaData;
__weak IBOutlet UIPickerView *pkSocialMedia;
__weak IBOutlet UILabel *lblGraph;
}
#end
PickerView delegate methods:
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
// Get key of requested row
NSString *title = [[lMediaTypes objectAtIndex:row] capitalizedString];
// Capitalize first letter
title = [title capitalizedString];
// Return
return title;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
// Make or clear data lists
if( lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] == nil ){
lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] = [[NSMutableArray alloc] init];
}
else{
[lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] removeAllObjects];
}
if( lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] == nil ){
lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] = [[NSMutableArray alloc] init];
}
else{
[lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] removeAllObjects];
}
// Get required key
NSString *dictKey = [lMediaTypes objectAtIndex:row];
if( [dictKey isEqualToString:#"total_views"] ){
return;
}
// Adjust graph label
lblGraph.text = [NSString stringWithFormat:#"Stats from %#", dictKey];
// Get data of selected row
NSArray *mediaData = [lMediaData objectAtIndex:row];
// Add each day to data lists: inversed order
for( int day = [mediaData count]-1; day >= 0; day-- ){
NSDictionary *dayData = [mediaData objectAtIndex:day];
dictKey = #"wpsd_trends_date";
NSString *date = [dayData objectForKey:dictKey];
// Remove 00:00:00
date = [date stringByReplacingOccurrencesOfString:#" 00:00:00" withString:#""];
[lGraphDayDataX[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] addObject:date];
dictKey = #"wpsd_trends_stats";
NSString *stats = [dayData objectForKey:dictKey];
[lGraphDayDataY[iSelectedServerIndex][DATATYPE_SOCIALMEDIA] addObject:stats];
}
// Update the graphs
[self updateGlobalScreen];
}
PickerView datasource methods:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [lMediaTypes count];
}
Deallocation:
- (void)dealloc
{
pkSocialMedia = nil;
lblGraph = nil;
lMediaData = nil;
lMediaTypes = nil;
}
I only recently converted the project to Objective-C ARC, so there is a good chance this issue has something to do with my lack of experience with the concept. Apart from that, this is also my first Xcode project ever. Hopefully, someone here can help out: please let me know if I need to post more code to clarify things.
Thanks in advance!
Try removing the -(void)dealloc method. It shouldn't be implemented when you're using ARC. If you aren't using ARC, it needs to call [super dealloc].
Never found the solution itself, so I used a workaround: by replacing the NSPickerView with a NSTableView component, the leak did not occur anymore. For everyone who noticed the issue and tried to find a solution: thank you for trying!
I'm having a similar issue. It only happens when the UIPickerView is outside the bounds. The way I fixed it is to never have the UIPickerView move out of bounds (simply fade in and fade out to unhide/hide the UIPickerView). Probably a bug in UIKit.