Standardizing styles for programmatically generated elements - ios

I started creating all elements programmatically and I repeat most of the code for styling the fields (e.g. borderStyle, keyboardType, keyboardAppearance, spellCheckingType, etc.).
What is the most acceptable way of doing this from one place?
Analogue would be CSS - I would define the general styles in one place, and all generated elements would use them automatically.
Thanks!

If I kept wanting UITextFields with a certain setup, my preferred approach would be to add a factory method to UITextField:
#implementation UITextField (DHFactory)
+ (instancetype)dh_textField {
UITextField *textField = [[self alloc] init];
[textField setKeyboardAppearance:UIKeyboardAppearanceAlert];
[textField setSpellCheckingType:UITextSpellCheckingTypeNo];
return textField;
}
#end
I prefixed the category method name, following the advice in Appleā€™s Programming with Objective-C.

Related

Prevent custom class from being altered by a category

Let's assume we have a custom lib with a class that inherits from UILabel:
//MyLibCustomLabel.h
#interface MyLibCustomLabel : UILabel
MyLibCustomLabel is linked to a UILabel in a .xib file, and text is filled in .xib.
This custom lib is integrated in a project that has a Category on UILabel class, which has a method to modify UIlabel's text
//UILabel+UILabelAdditions.h
#interface UILabel (UILabelAdditions)
//UILabel+UILabelAdditions.m
#implementation UILabel (UILabelAdditions)
- (void)awakeFromNib {
[super awakeFromNib];
[self prependText];
}
-(void)prependText {
NSString *newText = [NSString stringWithFormat:#"blabla + %#", self.text];
self.text = newText;
}
In the end, there is a modification non-desired in MyLibCustomLabel.
In a situation of both custom class and category are used in a Class, is there a way to protect MyLibCustomLabel from any Category on UILabel ?
So that MyLibCustomLabel can not be altered in an undesired way, and so that there is no modification to do in the project that integrates it.
Thanks for your help !
There is nothing that can be done to "protect" a class from a possible category being defined.
But please note that the example UILabel category you show isn't valid. A category must never attempt to override an existing method nor attempt to call a super method. Such behavior isn't defined and isn't guaranteed to work as hoped.
In other words, the category's awakeFromNib method is a bad idea and shouldn't be done. Such a thing should only be attempted in a base class, not a category.

How to set a default keyboard across an entire iOS app?

I have an iPad app that uses thousands of UITextFields and UITextViews throughout it. When text is being entered into these elements, the iOS default keyboard is used. However, because my app does not provide dictation support, it crashes whenever the user attempts to dictate. Some research into the subject has shown that it isn't possible to disable the dictation feature on the default keyboard.
Instead, I found that it is recommended to use a change the type of keyboard to one that doesn't offer a dictation option. The problem is that I have thousands of UITextFields and UITextViews throughout my app, so manually going in and changing the keyboard type of each of these is unfeasible. My question is this: is there a way to change the default keyboard used within an app?
One way to go about doing this is to use a category and set the value during init. This requires swizzling, but should be safe.
Keep in mind that this will do what you are requesting, so ALL UITextFields will now present using the defined keyboard type (even if you didn't instantiate the text field yourself).
This category will default all UITextFields to display the number pad.
#import "UITextField+KeyboardType.h"
#import <objc/runtime.h>
#implementation UITextField (KeyboardType)
+(void)initialize {
Method originalMethod = class_getInstanceMethod([self class], #selector(init));
Method swizzledMethod = class_getInstanceMethod([self class], #selector(init_swizzled));
method_exchangeImplementations(originalMethod, swizzledMethod);
}
- (instancetype)init_swizzled {
self = [self init_swizzled];
if (self) {
self.keyboardType = UIKeyboardTypeNumberPad;
}
return self;
}
#end
I would recommend that you instead create subclasses of UITextField/UITextView and replace all existing instances of UITextField/UITextView with their new subclasses.

calling a delegate before assigning text to UILabel text property

I don't know if I have chosen right title for my question.
I have developed an app and now I want to process text before assigning text to UILabel or UIView text property.
instead of
myLabel.text = story.text
do this:
myLabel.text = [story.text substituteCharactersOfText];
substituteCharactersOfText is a method of Category I have added to NSString class
so if I have a lot of label or another views, it will be difficult or errorProne to manually call this category method. (maybe I forgot one for anotherLabel.text)
so is there anyway to call this method automatically before assigning text to UILabel.text?
I think maybe there is way in objective-c I don't aware of (maybe an special use of delegate)!!
Subclass UILabel and override setText:
#implementation HALabel
- (void)setText:(NSString *)text {
[super setText:[text substituteCharactersOfText]];
}
#end

iOS SDK: about using properties when creating objects programmatically?

okay below is a standard example of creating a datepicker
- (void)viewDidLoad {
CGRect pickerFrame = CGRectMake(0,250,100,100);
UIDatePicker *myPicker = [[UIDatePicker alloc] initWithFrame:pickerFrame];
[myPicker addTarget:self action:#selector(pickerChanged:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:myPicker];
[myPicker release];
}
- (void)pickerChanged:(id)sender
{
NSLog(#"value: %#",[sender date]);
}
this is all good and well. I'm a little used to creating elements in IB so when I create an object programatically I'm not sure how to access the data.
What I mean is.. should I assign myPicker to a class property and then access it as _myPicker?
Or lets say I want to access the date inside of the pickerChanged method without calling another method. Should I assign an NSDate property and re-assign it every time the picker is changed?
I ran into some memory issues when I was trying to do it that way. I had another method grabbing _theDate, and it probably tried to access it at the same time pickerChanged was modifying it?
Anyway, what I'm getting at is "whats the proper workflow when creating things like action sheets, and pickers programmatically". When these things are changed, how should the resulting data be saved so the rest of the class can access it?
Bonus question:
Is there a difference between this?
for(UILabel *myLabel in view.subviews){
NSLog(myLabel.text);
}
and this? Do I need to check the class all the time if i know my view only contains a certain kind of object?
for((id) myLabel in view.subviews){
if([myLabel isKindOfClass:[UILabel class]){
UILabel *theLabel = myLabel;
NSLog(myLabel.text);
}
}
Generally, you will just define properties if you'll need to access them more than once. You can do this in the .m file's interface:
#interface MyObject()
#property (weak, nonatomic) UIDatePicker *myPicker;
#end
You will then be able to access it by either _myPicker or self.myPicker.
You shouldn't need another NSDate property in your class because you can access the set date at any time:
_myPicker.date
For your last question: the latter of the two is merely extra sanity checks. While you're writing your own code, and you should know what subviews you're adding in, it can't hurt to double check the type of the subviews incase anything should go wrong and you try to access selectors that don't exist. This is a larger programming question though and not necessarily objective-c or iOS specific.
The documented approach is to intercept the UIControlEventValueChanged event, as per your example.
You would then typically copy the [sender date] value to a property in your pickerChanged: method.
If the user hits a save button, then the object that presented the view containing the picker should be able to retrieve the selected date via the property.
It's not considered good practice to use isKindOfClass:. You should structure your code such that you always know what class you're dealing with.
Also, you should really switch to ARC so you don't need to worry about calling release
You need to declare a UIDatePicker property to hold one instance of your child controller
This is what you need to add in your .h file:
#property (strong, nonatomic) UIDatePicker *myPicker;
And then in your .m file you need to add a data source method for this date picker. something like what rdelmar has instructed above:
self.myPicker = [[UIDatePicker alloc] init];

Editing multiple dynamically generated UITextFields at runtime

I have made an application in which user may generate as many UITextField as he/she wants and those will be automatically placed over a UIView. Functionality is that user may drag the any of the UITextField at any point of screen.Till this part every thing is quite working. Now if he wants to edit the UITextField he taps(2 times) on UITextField and edits.This part of mine is only working for the recent generated UITextField not for all. How can i do this? I fnay one wants my previous code i can post. Plese respond it sonn. Thanks in advance.
add textFieldArray to .h file then specify <UITextFieldDelegate> and
sythesize that array.
while creating the each textfield
specify delegate like this
mytextF1.delegate=self;
mytextF2.delegate=self;
.....
after that add all text field object to an textFieldArray which should be declared .h file and synthesize them .(dont forget to alloc and init this array in ur viewdidload).
self.textFieldArray=[[NSMutableArray alloc]init];
then add each text field to this array
[self.textFieldArray addObject:mytextF1];
[self.textFieldArray addObject:mytextF2];
.......
then use this delegate methode to update
- (void)textFieldDidBeginEditing:(UITextField *)textField{
for (UITextField *textF in self.textFieldArray) {
[textF setText:[textField text]];
}
}

Resources