how can I apply haptic feedback throughout my app for every touchupinside event of every UIButton without writing code for each individual button? I have tried making a UIButton category and overriding - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event but this messes up some of my UIButton actions, (i may have implemented it badly)
does anyone have any suggestions?
Overriding in categories such kind of methods that mentioned #ChoungTran isn't such good idea. If you want to customize the default methods in a Category, it'd be better to do that in a swizzled method.
But, I'll prefer to make a custom class derived from UIButton, and implement that logic there and use that button everywhere where I need haptic.
From Apple documentation:
Although the Objective-C language currently allows you to use a
category to override methods the class inherits, or even methods
declared in the class interface, you are strongly discouraged from
doing so. A category is not a substitute for a subclass. There are
several significant shortcomings to using a category to override
methods:
When a category overrides an inherited method, the method in the
category can, as usual, invoke the inherited implementation via a
message to super. However, if a category overrides a method that
exists in the category's class, there is no way to invoke the original
implementation.
A category cannot reliably override methods declared in another
category of the same class.
This issue is of particular significance because many of the Cocoa
classes are implemented using categories. A framework-defined method
you try to override may itself have been implemented in a category,
and so which implementation takes precedence is not defined.
The very presence of some category methods may cause behavior changes
across all frameworks. For example, if you override the
windowWillClose: delegate method in a category on NSObject, all window
delegates in your program then respond using the category method; the
behavior of all your instances of NSWindow may change. Categories you
add on a framework class may cause mysterious changes in behavior and
lead to crashes.
Try to use category with class UIButton. In UIButton-Extention register event forControlEvents:UIControlEventTouchUpInside
#import "UIButton+Extention.h"
#implementation UIButton (Extention)
- (instancetype)init
{
self = [super init];
if (self)
{
[self addTarget:self action:#selector(customTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void)awakeFromNib
{
[super awakeFromNib];
[self addTarget:self action:#selector(customTouchUpInside:)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)customTouchUpInside:(UIButton *)sender
{
//TODO:
NSLog(#"Do something here...");
}
#end
Updated: Register event when UIButton created programmatically
Related
I have a textView "TexV" which have a custom class "TexV_Class" inherited from UITextView and I have a viewController "VC" with custom class named "VC_Class"
Now how can I make both classes "TexV_Class" and "VC_Class" delegate and make them work together? Is it even possible that same delegate method (eg. textViewDidChange) in BOTH classes runs (leaving the sequence of running for now)
I although had made both classes delegate but only one runs (that of VC_Class having textView delegate methods run)
You can't. The delegate mechanism works by having a single callback object, if you want more than one item to react based on the delegate you can go around this in one of two ways:
1- Fire a notification on one of your delegate so that the other delegate can act accordingly
2- set a custom delegate on TexV_Class that conforms to the method of UITextView that the VC_Class wants to adopt, and have TexV_Class call this delegate from it's delegate callback.
I suggest you 3 ways to do this:
1) Use NSNotificationCenter (the pattern help 1 object communicate one-to-many objects)
2) Use multicast delegate pattern. Implementation detail, you can refer this http://blog.scottlogic.com/2012/11/19/a-multicast-delegate-pattern-for-ios-controls.html
3) Use Proxy Design pattern. (This way I choosen)
class MyTextView.h
#protocol NJCustomTextViewDelegate <NSObject>
- textViewShouldBeginEditing:
- textViewDidBeginEditing:
- textViewShouldEndEditing:
- textViewDidEndEditing:
#end
#property (nonatomic, weak) id< NJCustomTextViewDelegate >textViewDelegate;
Use this:
in MyTextView.m
self.delegate = self;
- (void)textViewShouldBeginEditing:(UITextView)textView
{
// Handle business logi
// .... Do your logic here
if ([self.textViewDelegate responseToSelector:#selector(textViewShouldBeginEditing:)])
{
[self.textViewDelegate textViewShouldBeginEditing:self];
}
}
In MyViewController.m
MyTextView textView = ....
textView.textViewDelegate = self;
I have this myViewController, that instantiates instances of itself.
Currently, I have a UIButton, that triggers the method
-(void)somethingImportant
However, I want that somethingImportant to happen during the ViewDidLoad, so I don't have to push that button.
But if I put somethingImportant in the ViewDidLoad of myViewController, it is recursively called as many times I have a subview of myViewController.
I tried to put somethingImportant in the application didFinishLaunchingWithOptions: of my app delegate, but somehow that does't work either.
EDIT
So here's the code that might be relevant. I have this UIScrollView with a lot of subviews of myViewController:
- (void)configureScrollView
{
for (int i = 0; i < [self.childViewControllers count]; i++) {
...
myViewController * theSubview =[self.childViewControllers objectAtIndex:i];
....
[theScrollView addSubview:[theSubview view]];
}
}
What is the best approach to make sure that somethingImportant is called only once?
I have this class, that instantiates instances of itself.
This inherently sounds like a bad idea and can easily lead to recursion if you're not careful. Therefore I would suggest you rethink your logic. If you need multiple instances of a class, you should be managing those instances from outside that class, not from within.
However, if you're still insistent on doing this - you can do something similar to what sschale suggests and use a variable to keep track of whether you've called your method or not.
The thing is you'll need to define this variable as static in order for it to be stored at class scope, not instance scope.
For example:
static BOOL firstCalled = NO;
- (void)viewDidLoad {
[super viewDidLoad];
if (!firstCalled) {
firstCalled = YES;
[self foo];
}
}
Each subclass should be calling [super viewDidLoad], on up the chain, so that code really should only be called once.
However, if you need to make sure it executes only once, add #property (nonatomic) BOOL runOnce; to that file's interface, and then in -(viewDidLoad) do:
if(!self.runOnce) {
//all code that is only run once
self.runOnce = YES;
}
Is it possible to intercept all user actions like tap, swipe, enter text, etc. on all windows of my app?
Like I said in the comments, subclass UIApplication and override the instance method sendEvent:.
From the documentation for the UIApplication class, -sendEvent: method:
Discussion
If you require it, you can intercept incoming events by
subclassing UIApplication and overriding this method. For every event
you intercept, you must dispatch it by calling [super sendEvent:event]
after handling the event in your implementation.
So, it would look like this:
CustomUIApplication.h:
#interface CustomUIApplication:UIApplication
- (void)sendEvent:(UIEvent *)event;
#end
CustomUIApplication.m:
#implementation CustomUIApplication
- (void)sendEvent:(UIEvent *)event
{
// ...Do your thing...
[super sendEvent:event];
}
#end
Of course, you need to make sure your subclass is used instead of the default UIApplication. Here is a Stack Overflow answer on how to do it in Objective-C, and here in Swift.
Simple question: what is the standard method of creating a customized version of say a UILabel, UIButton, etc. such that I can easily use it in multiple places? Is it simply to extend the appropriate class:
import UIKit
class FormField: UITextField {
override init()
{
super.init()
// borderStyle = UITextBorderStyle.None
}
}
Basically just want to get some default values set for some UI objects so I can easily drop them into the interface when necessary. Not really sure how to get this working.
It is very rare to subclass something like UILabel.
The most common approach is a HAS-A pattern, where you let a controller (often a UIViewController) manage the view for you and you reuse that. Alternately, you may make a UIView that contains the view you want to customize, and customizes it for you (passing along things that need to be passed along).
You can also have a "configure my view this way" function that you can call on an existing standard view. I haven't seen this very often in reusable code. My experience is that these kind of configuration functions turn out to be very app specific, but they're reasonable common.
Things like UITextField have delegate methods already, and a common way to customize them is to create a reusable delegate that applies certain behaviors.
It depends of course on what you're trying to achieve, but subclassing is pretty far down on the list of patterns, unless it's a class explicitly designed and documented to be subclassed (like UIView or UIViewController).
UIView and its subclasses have two designated initializers, -initWithFrame: and -initWithCoder:. The first is for programmatic instantiation while the latter is for views being unpacked from a Storyboard or NIB. Because of this, the common pattern for subclassing UIView subclasses is the following (I'm using ObjC but the Swift code should be easy to figure out):
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self) {
[self commonInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if(self) {
[self commonInit];
}
return self;
}
- (void)commonInit {
// Do your special setup here!
}
Then, if you're using the views in Interface Builder, go to the Identity tab on the right-assistant-editor-sidebar, and in the top box where it says UILabel or UIButton, put in your custom button class name.
Hopefully this clears things up a bit.
Im trying to make it so that every single UIControl in my application (UIButton, UISlider, etc) all have special extra properties that I add to them.
I tried to accomplish this by creating a UIControl Category and importing it where needed but I have issues.
Here is my code.
My setSpecialproperty method gets called but it seems to be getting called in an infinite loop until the app crashes.
Can you tell me what Im doing wrong or suggest a smarter way to add a property to all of my UIControls?
#interface UIControl (MyControl)
{
}
#property(nonatomic,strong) MySpecialProperty *specialproperty;
-(void)setSpecialproperty:(MySpecialProperty*)param;
#end
////////
#import "UIControl+MyControl.h"
#implementation UIControl (MyControl)
-(void)setSpecialproperty:(MySpecialProperty*)param
{
self.specialproperty=param;
}
///////////////
#import "UIControl+MyControl.h"
#implementation ViewController
UIButton *abutton=[UIButton buttonWithType:UIButtonTypeCustom];
MySpecialProperty *prop=[MySpecialProperty alloc]init];
[abutton setSpecialproperty:prop];
While you can't add an iVar to UIControl via a category, you can add Associated Objects, which can be used to perform much the same function.
So, create a category on UIControl like this:
static char kControlNameKey;
- (void) setControlName: (NSString *) name
{
objc_setAssociatedObject(self, &kControlNameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *) controlName
{
return (NSString *)objc_getAssociatedObject(array, &kControlNameKey);
}
There's more to it than that, I guess you'll need to check if an association exists before setting a new one, otherwise it will leak, but this should give you a start.
See the Apple Docs for more details
self.specialproperty=param is exactly the same as calling [self setSpecialproperty] (see here for some totally non biased coverage of Obj-C dot notation), which makes your current usage infinitely recursive.
What you actually want to do is:
-(void)setSpecialproperty:(MySpecialProperty*)param
{
_specialproperty = param;
}
Where _specialproperty is the implicitly created ivar for your property.
I'm assuming there's some reason why you've implemented your setSpecialproperty setter? Why not just use the one that is implicitly created for you?
the problem is that you can not add a property to a category, you can add behavior (methods) but not properties or attributes, this can only be done to extensions, and you can not create extensions of the SDK classes
use your method as
change your method name to
-(void)setSpecialproperty:(MySpecialProperty *)specialproperty
-(void)setSpecialproperty:(MySpecialProperty*)specialproperty
{
if(_specialproperty!=specialproperty)
_specialproperty = specialproperty;
}
and synthesize your specialProperty as
#synthesize specialproperty=_specialproperty;