Aster finding myself in the situation of wanting to disable a UIPickerView component and not finding any answers that uses the default functionality but tries to go around it by using labels or multiple UIPickerViews, I start poking around the UIPickerView structure in order to find a more direct approach to solve the problem by using the OS already present functionality.
So these is my answer, what I found by trial and error, and the way that I am using it:
The method:
- (void)dissableUIPickerViewComponent:(int)componentToDissable forPickerView:(UIPickerView *)pickerView{
NSArray *pickerViews = [[NSArray alloc] initWithArray:[pickerView subviews]];
UIView *mainSubview;
for (int count = 0; count < pickerViews.count; count++) {
UIView *temp = [pickerViews objectAtIndex:count];
if (temp.frame.size.height > 100) {
mainSubview = temp;
}
}
NSArray *componentSubview = [mainSubview subviews];
while ([[[[componentSubview objectAtIndex:componentToDissable] subviews] firstObject] superview].gestureRecognizers.count) {
[[[[[componentSubview objectAtIndex:componentToDissable]subviews]firstObject]superview] removeGestureRecognizer:[[[[[componentSubview objectAtIndex:componentToDissable]subviews]firstObject]superview].gestureRecognizers objectAtIndex:0]];
}
}
Best place to call:
- (void)viewDidAppear:(BOOL)animated{
[self dissableUIPickerViewComponent:0 myPickerView];
}
I hope these will help others that found themself in the same position that I did :)
Related
Please can anyone tell me why this piece of code isn't working? I've got a dictionary which contains UIViews with tables inside associated with the keys which are the names of the corresponding buttons (there are a lot of them). So what I actually want to do is to change the view visibility on the corresponding button click. But the issue is that the expression to do that is not accepted by Xcode and I get the Expected Identifier error.
- (IBAction)choosingButtonClicked:(id)sender {
if ([sender currentTitle]) {
[(UIView *)[self.selectionTables objectForKey:[sender currentTitle]]].hidden = ![(UIView *)[self.selectionTables objectForKey:[sender currentTitle]]].isHidden;
}
}
First of all, with all due respect, I agree with trojanfoe comments. Its not working because its not properly written.
Now, lets try to streamline it with below code:
- (IBAction)choosingButtonClicked:(id)sender {
NSString *title = [sender currentTitle];
if (title) {
UIView *selectionView = (UIView *)self.selectionTables[title];
selectionView.hidden = !selectionView.isHidden;
}
}
Your code is too complex, because of that even the author can't understand it. If we re-write your code using local variables, it will look like:
- (IBAction)choosingButtonClicked:(id)sender
{
NSString *title = [sender currentTitle];
if (title)
{
UIView *tempView = (UIView *)[self.selectionTables objectForKey:title];
[tempView].hidden = ![tempView].isHidden;
}
}
If you check the code now, you can see that the following code is causing the issues:
[tempView].hidden = ![tempView].isHidden;
Change your method like:
- (IBAction)choosingButtonClicked:(id)sender
{
NSString *title = [sender currentTitle];
if (title)
{
UIView *tempView = (UIView *)[self.selectionTables objectForKey:title];
tempView.hidden = !(tempView.isHidden);
}
}
I am currently using default UISwitch.
Is it possible to set image instead of thumbTintColor property and also change image when state is on or off? Is it possible in default switch or should I use custom switch?
UISwitch has the onImage and offImage UIImage properties. Set these after initialization and they will toggle automatically when the on state changes.
I found interesting solution may be it helps.
NSArray *array = [self.mySwitch subviewsWithClass:[UIImageView class]];
for (UIImageView *imageView in array) {
imageView.image = [UIImage imageNamed:#"btn-youtube.png"];
}
Hear I used method from UIView category
- (NSArray*)subviewsWithClass:(Class)class
{
NSMutableArray *array = [NSMutableArray array];
if ([self isKindOfClass:class]) {
[array addObject:self];
}
for (UIView *subview in self.subviews) {
[array addObjectsFromArray:[subview subviewsWithClass:class]];
}
return array;
}
Image size is {57, 43.5}. Circle radius is 15(with shadow)
I understand that it is not very good way to solve. But if you really need it helps.
I'm working on an iPhone game and currently the game uses many UIImageViews to show space ships, bullets and other things. The game probably has 30-40 different subviews in the view controller and I've decided that I should probably programmatically add subviews when they are needed rather than starting the game with them in the hidden state and making them unhidden when needed (for performance issues) so here are my questions:
(1) will there be a significant performance gain from adding subviews when needed?
(2) how do I release a subview when ARC is enabled? Im trying to add the views (based on type) into an NSMutableArray when its created to hold it, and removing it from the array when I'm done using it, does removing it from the array deallocate that memory?
heres the code (theres an NSTimer that runs the movement method every 0.03 seconds, and the get and set methods are on an "instance variable" NSMutableArray);
-(void)movement {
if (shootButton3.isHighlighted) {
NSMutableArray *array = [self getBulletArray];
[self setarray:array];
}
[self shootBullet: [self getArray]];
}
-(NSMutableArray *)getBulletArray {
UIImageView *bullet = [[UIImageView alloc] initWithFrame:CGRectMake(ship.center.x + 20, ship.center.y, 15, 3)];
bullet.image = [UIImage imageNamed:#"bullet2.png"];
bullet.hidden = NO;
[self.view addSubview:bullet];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:bullet];
return array;
}
-(void)shootBullet: (NSMutableArray *)bulletArray {
for (int i = 0; i < [bulletArray count]; i++) {
UIImageView *bullet = [bulletArray firstObject];
bullet.center = CGPointMake(bullet.center.x + 4, bullet.center.y);
if (bullet.center.x > 500) {
bullet.hidden = YES;
[bulletArray removeObjectAtIndex:0];
}
}
}
-(void)setarray:(NSMutableArray *) array {
bulletArray = array;
}
-(NSMutableArray *)getArray {
return bulletArray;
}
To answer your two questions:
Question 1: Yes, there will be a performance increase for sure, regardless of how large the UIImageViews are.
Question 2: Simply set the imageView to nil: self.imageView = nil;
I am having multiple textfields in my screen. I am receiving a JSON response named as validation for all the text fields. What I actually want is that I should be able to set the validation for these text fields as soon as the user is not in the range of normal values. i have prepared a logic for that: The code is as follows
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField;{
// Here we are checking if TextField is not equals to blank then we are performing
validations here.
if (![textField.text isEqualToString:#""]) {
NSLog(#"%#",textField.UID);
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"column_name == %#",
textField.UID];
NSArray * arr = [[NSArray alloc] init];
arr = [arr_vitalvalidations filteredArrayUsingPredicate:predicate];
for (int i=0; i < [arr count]; i++) {
NSString * str_maxValue = [[arr objectAtIndex:i] valueForKey:#"max_value"];
NSString * str_minValue = [[arr objectAtIndex:i] valueForKey:#"min_value"];
if ([textField.text floatValue] > [str_maxValue floatValue] || [textField.text
floatValue] < [str_minValue floatValue]) {
NSString * str_message = [[arr objectAtIndex:i]
valueForKey:#"message_note"];
str_message = [str_message stringByReplacingOccurrencesOfString:#"%1"
withString:str_minValue];
str_message = [str_message stringByReplacingOccurrencesOfString:#"%2"
withString:str_maxValue];
DisplayAlert(str_message)
[textField becomeFirstResponder];
return NO;
}
}
}
return YES;
}
This code actually makes the other textfields dormant as now I can't switch to the Other textfields until I put the right values in the First textfield. I too have other controls on my screen but they are working fine. for example a Segment controller to change the value of Height in cm to feet. This segment controller is still working and is rightly so changing the values which I have to prevent. Moreover on pressing the Back button in order to leave this screen this code shows the Alert message 4 times. Please help me in resolving this issue. A little help will be greatly appreciated.
give some image of your screen. also, y would u want to restrict user interaction because user has not entered a correct field?
PS: I cannot comment, that is why i am putting this as an answer
for solving your problem try like this it'l helps you but i don't know is it correct way or not.
take one global variable and update the value and compare that value in textFieldShouldEndEditing
method and perform the operation as you want.
-(IBAction)backBtnAction:(id)sender{
NSLog(#"close down ");
n=10;
[textfield resignFirstResponder];
}
replace your condition with below line
if (![textField.text isEqualToString:#""] & n!=10)
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.