I want create a class that can inherit from two custom class.
Do you have any idea to do this please?
Please see below my example:
first class:
#interface UIZoomableView : UIView
{
UITapGestureRecognizer *_tapGestureRecognizer;
}
and implementation:
- (void)onDoubleTap:(UITapGestureRecognizer *)sender
{
CGSize newSize;
CGPoint centerPoint = self.center;
if ([self isSmall])
{
newSize = [self bigSize];
}
else
{
newSize = [self smallSize];
}
[UIView animateWithDuration:0.3 animations:^{
self.size = newSize;
self.center = centerPoint;
}];
}
Second class:
#interface UIDraggableView : UIView
UIPanGestureRecognizer *_panGestureRecognizer;
#end
implementation:
- (void)handlePan:(UIPanGestureRecognizer*)sender
{
..
}
i want to create a custom view that can be zoomable and draggable.
Do you have any idea to do this please? (without copy code..)
I think something like protocols but i want default value for the base classes?
How can i implement this using protocol or something like protocols.
Thanks for any response!
Objective-C doesn't support multiple inheritance. You could use a protocol, composition and message forwarding to achieve the same result.
A protocol defines a set of methods that an object must implement (it's possible to have optional methods too). Composition is basically the technique of include a reference to another object and calling that object when it's functionality is required. Message forwarding is a mechanism that allows objects to pass messages onto other objects, for example, an object that is included via composition.
Apple Reference:
Protocols
Composition
Message Forwarding (and specifically Forwarding and Multiple Inheritance)
So, in your case Composition might be a solution, below is the example code
#interface ClassA : NSObject {
}
-(void)methodA;
#end
#interface ClassB : NSObject {
}
-(void)methodB;
#end
#interface MyClass : NSObject {
ClassA *a;
ClassB *b;
}
-(id)initWithA:(ClassA *)anA b:(ClassB *)aB;
-(void)methodA;
-(void)methodB;
#end
#implementation MyClass
-(id)initWithA:(ClassA *)anA b:(ClassB *)aB {
a = anA ;
b = aB ;
}
-(void)methodA {
[a methodA] ;
}
-(void)methodB {
[b methodB] ;
}
#end
If you don't want to implement all the methods from ClassA and ClassB in MyClass, you can use Message Forwarding in MyClass to handle all the method invocations. Below works fine as long as ClassA and ClassB do not have any common methods.
#implementation MyClass
-(id)initWithA:(ClassA *)anA b:(ClassB *)aB {
a = anA ;
b = aB ;
}
//This method will be called, when MyClass can not handle the method itself
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([a respondsToSelector:[anInvocation selector]])
[a invokeWithTarget:someOtherObject];
else if ([b respondsToSelector:[anInvocation selector]])
[b invokeWithTarget:someOtherObject];
else
[super forwardInvocation:anInvocation];
}
#end
The closest that you can get to multiple inheritance in Objective C is with categories. These are a mechanism for adding additional methods to a class that already exists.
Note that this has some important limitations:
You can't add properties or ivars using a category, though you can use associated objects to get a similar effect;
The compiler won't tell you if you have methods with the same name that are declared in the class and the category, or in two categories, so you have to be careful to avoid name collision;
This won't appear as a proper class (because Objective C does not have multiple inheritance) so you won't have something in your code called ScrollableZoomableView which inherits from ScrollableView and ZoomableView. That's not possible in Objective C (unlike C++ for example).
You need the -ObjC flag when linking files with categories, otherwise you'll get unrecognized selector errors when you run your code;
You can't get your code called during -init or +initialize, because those belong to the base class. You'll need to initialize your properties explicitly. You can still use +load though;
You can't intercept dealloc either, so you may need to be careful to explicitly deregister your listeners too.
You want something like this:
#interface UIView (Zoomable)
#property (nonatomic) UITapGestureRecognizer * my_tapGestureRecognizer;
#end
#implementation UIView (Zoomable)
-(void)my_enableZooming() {
self.my_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(my_onDoubleTap:)];
self.my_tapGestureRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:self.my_tapGestureRecognizer];
}
-(void)my_disableZooming() {
[self removeGestureRecognizer:self.my_tapGestureRecognizer];
self.my_tapGestureRecognizer = nil;
}
-(void)my_onDoubleTap:(UITapGestureRecognizer *)sender {
...
}
-(UITapGestureRecognizer)my_tapGestureRecognizer {
return objc_getAssociatedObject(self, #selector(my_tapGestureRecognizer));
}
-(void)setMy_tapGestureRecognizer:(UITapGestureRecognizer)value {
objc_setAssociatedObject(self, #selector(my_tapGestureRecognizer), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
#interface UIView (Draggable)
#property (nonatomic) UIPanGestureRecognizer * my_panGestureRecognizer;
#end
#implementation UIView (Draggable)
-(void)my_enableDragging() {
self.my_panGestureRecognizer = ...;
}
-(void)my_disableDragging() {
...
}
-(void)my_handlePan:(UIPanGestureRecognizer*)sender {
...
}
-(UIPanGestureRecognizer)my_panGestureRecognizer {
return objc_getAssociatedObject(self, #selector(my_panGestureRecognizer));
}
-(void)setMy_panGestureRecognizer:(UIPanGestureRecognizer)value {
objc_setAssociatedObject(self, #selector(my_panGestureRecognizer), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
Related
I want to create object of generic property with default initializer. I know this is possible in swift by adding an init method in MyProtocol. Is there any way I can achieve this functionality in objective c
Interface
#interface CustomClass<__covariant T:id<MyProtocol>> : NSObject
#property(nonatomic) T result;
-(void) update;
#end
Implementation
#import "CustomClass.h"
#implementation CustomClass
-(void) update
{
//self.result = initialize result here
[self.result myMethod];
}
#end
Objective-C is late binding and dynamic typing. Neither you need templates (ooops, they call it generics) nor the compiler bind to it. Simply use id.
#interface CustomClass : NSObject
#property(nonatomic) id result;
-(void) update;
#end
-(void) update
{
//self.result = initialize result here
[self.result myMethod];
}
If you want to have a constraint on the type for whatever reason, simply use the protocol:
#protocol CustomProtocol
- (void)myMethod;
#end
#interface CustomClass : NSObject
#property(nonatomic) id<MyProtocol> result;
-(void) update;
#end
-(void) update
{
//self.result = initialize result here
[self.result myMethod];
}
After discussion the subject in the comments:
If you want to instantiate a generic type, you do not do this at compile time, but simply pass the type to the initializer at runtime.
Instead of …:
var concrete = CustomClass<Concrete>()
… you write:
CustomClass *concrete = [[CustomClass alloc] initForType:[Concrete class]];
Personally I prefer new allocators, but this is another discussion. You can pass the types name as string, too. Personally I do not like that, too. :-)
The initializer looks like this:
- (instancetype)initForType:(Class)type
{
if( (self = [super init] )
{
self.result = [type new];
}
return self;
}
Lightweight generics in Objective-C are a purely compile-time construct to aid in type checking. They are erased after type-checking and do not exist in the compiled code. There is no T at runtime. You cannot write any code that needs to know what T is.
I have class ImageViewController. It has delegate:
#protocol ImageViewControllerDelegate
#optional
- (void)singleTapGestureRecognizer:(UITapGestureRecognizer *)gesture;
- (void)imageDidLoaded;
I also have class AttachmentViewController that subclass of ImageViewController. In that class I want to get event then image property in changed. So here is my code of it change:
- (void)setImage:(UIImage *)image
{
// * Assign image with animation
[UIView transitionWithView:self.imageView
duration:k_DURATION_imageAppearence
options:UIViewAnimationOptionTransitionCrossDissolve
animations: ^{
self.imageView.alpha = 1;
} completion:^(BOOL finished) {
if ([self respondsToSelector:#selector(imageDidLoaded)]) {
[self.delegate imageDidLoaded];
}
}];
But I can not use
if ([self.DELEGATE respondsToSelector:#selector(imageDidLoaded)])
Then I do it I have error:
No known instance method for selector 'respondsToSelector:'
Why? And how here I need to use this capabilities? Is my implementation ok? Or how can I get this notification?
I think that here will be ok to create clear methods in superclass and override it in subclass if it needs to implement is. Is it best way?
You should declare your protocol as #protocol ImageViewControllerDelegate <NSObject>
This says that any object that conforms to your protocol will also conform to the NSObject protocol that respondsToSelector: is declared in.
There's really not enough code here to understand what you're trying to do. Generally to setup a delegate you have a weak property on your class that represents the delegate, and a parent to that class's instance would set the delegate.
Here's some pseudo code:
#protocol SomeDelegateProtocol<NSObject>
- (void)someMethod:(id)someObject;
#end
#interface SomeClass:NSObject
#property (nonatomic, weak) id<SomeDelegateProtocol>delegate;
#end
#implementation SomeClass
- (void)someFunction {
if ([self.delegate respondsToSelector:#selector(someMethod:)]) {
// do code stuff
}
}
#end
///////////
#implementation SomeParentClass
- (void)someOtherFunction {
SomeClass *instance = [SomeClass new];
instance.delegate = self; // assuming self implements SomeDelegateProtocol, otherwise you get a warning
}
Hope this helps!
Let's say for example that I have MyUITextViewSubclass which inherits from UITextView and MyUITextFieldSubclass which inherits from UITextField and both of those subclasses contain a lot of the same methods and properties to add similar behavior to those UI controls.
Since UITextView and UITextField inherit from different classes, is there an easy way to create an abstract class to combine all of that repeated code? In other words, is it possible to create an abstract class that I could inherit from for both of those subclasses and then just override the methods that are different between the two?
What I know so far:
I know Objective-C doesn't support multiple inheritance (inheritance from two or more classes)
I know I could add common methods using Categories, but I don't think that solves overriding init methods or adding private properties
Building on Amin's answer, this is how you could do it:
Step 1: Create a TextSurrogateHosting protocol that will contain all the methods of your UITextField and UITextView subclasses that you need to access from the methods that you want to add to both subclasses. This might for example be a text and setText: method, so that your methods can access and set the text of either a text field or a text view. It might look like this:
SPWKTextSurrogateHosting.h
#import <Foundation/Foundation.h>
#protocol SPWKTextSurrogateHosting <NSObject>
- (NSString *)text;
- (void)setText:(NSString *)text;
#end
Step 2: Create a TextSurrogate class that contains all the methods that you want to share between both the UITextField and the UITextView subclasses. Add those methods to a protocol so that we can use code completion in Xcode and avoid compiler warnings/errors.
SPWKTextSurrogate.h
#import <Foundation/Foundation.h>
#import "SPWKTextSurrogateHosting.h"
#protocol SPWKTextSurrogating <NSObject>
#optional
- (void)appendQuestionMark;
- (void)appendWord:(NSString *)aWord;
- (NSInteger)characterCount;
- (void)capitalize;
#end
#interface SPWKTextSurrogate : NSObject <SPWKTextSurrogating>
/* We need to init with a "host", either a UITextField or UITextView subclass */
- (id)initWithHost:(id<SPWKTextSurrogateHosting>)aHost;
#end
SPWKTextSurrogate.m
#import "SPWKTextSurrogate.h"
#implementation SPWKTextSurrogate {
id<SPWKTextSurrogateHosting> _host;
}
- (id)initWithHost:(id<SPWKTextSurrogateHosting>)aHost
{
self = [super init];
if (self) {
_host = aHost;
}
return self;
}
- (void)appendQuestionMark
{
_host.text = [_host.text stringByAppendingString:#"?"];
}
- (void)appendWord:(NSString *)aWord
{
_host.text = [NSString stringWithFormat:#"%# %#", _host.text, aWord];
}
- (NSInteger)characterCount
{
return [_host.text length];
}
- (void)capitalize
{
_host.text = [_host.text capitalizedString];
}
#end
Step 3: Create your UITextField subclass. It will contain three necessary boilerplate methods to forward unrecognized method invocations to your SPWKTextSurrogate.
SPWKTextField.h
#import <UIKit/UIKit.h>
#import "SPWKTextSurrogateHosting.h"
#import "SPWKTextSurrogate.h"
#interface SPWKTextField : UITextField <SPWKTextSurrogateHosting, SPWKTextSurrogating>
#end
SPWKTextField.m
#import "SPWKTextField.h"
#implementation SPWKTextField {
SPWKTextSurrogate *_surrogate;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_surrogate = [[SPWKTextSurrogate alloc] initWithHost:self];
}
return self;
}
#pragma mark Invocation Forwarding
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([_surrogate respondsToSelector:[anInvocation selector]]) {
[anInvocation invokeWithTarget:_surrogate];
} else {
[super forwardInvocation:anInvocation];
}
}
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
NSMethodSignature* signature = [super methodSignatureForSelector:selector];
if (!signature) {
signature = [_surrogate methodSignatureForSelector:selector];
}
return signature;
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ([super respondsToSelector:aSelector] ||
[_surrogate respondsToSelector:aSelector])
{
return YES;
}
return NO;
}
#end
Step 4: Create your UITextView subclass.
SPWKTextView.h
#import <UIKit/UIKit.h>
#import "SPWKTextSurrogateHosting.h"
#import "SPWKTextSurrogate.h"
#interface SPWKTextView : UITextView <SPWKTextSurrogateHosting, SPWKTextSurrogating>
#end
SPWKTextView.m
#import "SPWKTextView.h"
#import "SPWKTextSurrogate.h"
#implementation SPWKTextView {
SPWKTextSurrogate *_surrogate;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_surrogate = [[SPWKTextSurrogate alloc] initWithHost:self];
}
return self;
}
#pragma mark Invocation Forwarding
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
if ([_surrogate respondsToSelector:[anInvocation selector]]) {
[anInvocation invokeWithTarget:_surrogate];
} else {
[super forwardInvocation:anInvocation];
}
}
- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector
{
NSMethodSignature* signature = [super methodSignatureForSelector:selector];
if (!signature) {
signature = [_surrogate methodSignatureForSelector:selector];
}
return signature;
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
if ([super respondsToSelector:aSelector] ||
[_surrogate respondsToSelector:aSelector])
{
return YES;
}
return NO;
}
#end
Step 5: Use it:
SPWKTextField *textField = [[SPWKTextField alloc] initWithFrame:CGRectZero];
SPWKTextView *textView = [[SPWKTextView alloc] initWithFrame:CGRectZero];
textField.text = #"The green fields";
textView.text = #"What a wonderful view";
[textField capitalize];
[textField appendWord:#"are"];
[textField appendWord:#"green"];
[textField appendQuestionMark];
NSLog(#"textField.text: %#", textField.text);
// Output: The Green Fields are green?
[textView capitalize];
[textView appendWord:#"this"];
[textView appendWord:#"is"];
NSLog(#"textView.text: %#", textView.text);
// Output: What A Wonderful View this is
This pattern should solve your problem. Hopefully :)
Some more background information is available here: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105
What you want is a mixin. This is not supported in Objective-C. Categories are no mixins, because they add an api to one class not to many (>1) classes. Using categories, what is not possible for many reasons as you said, would not help you.
The usual way to solve that problem is to create a helper class containing the additional code and use it in both classes.
Then you will find yourself typing
[myUITextViewSubclass.helper doSomething]
instead of
[myUITextViewSubclass doSomething]
If this is really a problem, you can solve this with forward invocations. Just write a comment.
No. It is not possible.
The closest thing you could achieve would be to manually add functionality to UITextView to make it mimic UITextField. The obvious downside is that you must do this all manually, with your own code.
You could use a preprocessor macro, but that is error-prone.
Traits or Mixins are not supported by Objective-C, you only have built-in option of Categories.
But fortunately Objective-C Runtime has almost all tools for implementing own idea if mixing or traits with adding methods and properties to your class at runtime. You can read more about opportunities which Objective-C Runtime provides for you on Apple's documentation website Objective-C Runtime Docs
The idea is:
1) You can create an Objective-C protocol (Mixin), in which you will declare properties and methods.
2) Then you create a class (Mixin implementation), which will implement methods from this protocol.
3) You make your some class, in which you want to provide the possibility of composition with mixins, to conform that protocol (Mixin).
4) When your application launches, you add with Objective-C runtime all implementations from (Mixin implementation) class and properties declared in (Mixin) into your class.
5) voilà :)
Or you can use some ready open source projects such as "Alchemiq"
I have an abstract interface in Objective-C where every sub-class needs to set up a property and then do the exact same thing with that property at the end of init. I'm trying to avoid duplicated code with something like this:
Interface File
#interface Shape : NSObject
#property (nonatomic) PropertyType *prop;
- (id)init;
- (void)initProperty;
#end
Implementation File
#implementation Shape
- (id)init
{
if(self = [super init]) {
[self initProperty];
[prop doSomething];
}
return self;
}
- (void)initProperty
{
}
#end
My problem is that every sub-class will need a different set of parameters passed to initProperty in order to implement the method correctly:
#implementation Rectangle
- (void)initPropertyWithRect:(CGRect)rect
{
prop = [RectangleStuff rectangleWithRect:rect];
}
#end
#implementation Circle
- (void)initPropertyWithRadius:(CGFloat)radius
{
prop = [CircleStuff circleWithRadius:radius];
}
#end
Is there a clean way to do what I'm trying to do in Objective-C? So far, my options seem to be:
Create a "property bag", and just pass around an NSDictionary.
Duplicate the [property doSomething]; code in every subclass.
Somehow pass in a factory object to init, and have the factory object create prop. This approach seems the cleanest, but I'd need the factory object to keep the rect and/or radius as internal state somehow, and that doesn't seem clean to me.
Any thoughts?
I would probably choose #2 (to keep it simple). If the property is only set once
(in the subclass init method), you could override the property setter method in the
superclass, and do the additional stuff there.
Untested code:
- (void)setProp:(PropertyType *)prop
{
_prop = prop; // (Assuming ARC)
[_prop doSomething];
}
First, I feel obligated to mention that your init function should not do anything besides initialize the object. That said, every rule has a time and a place to be broken, so I'll offer what suggestions I can.
Your init function is no different than any other function. You can do things before and after you call super. While generally discouraged, this would be a good place to do it. Your init in your subclass would now look like this:
- (id)init
{
self.myProperty = value;
self = [super init];
if (self) {
// more init stuff
}
return self;
}
I ended up using a variant of what was suggested in the other two answers:
Shape.h
#interface Shape : NSObject
#property (nonatomic) PropertyType *prop;
- (id)initWithProperty:(PropertyType *prop);
#end
Shape.m
#implementation Shape
- (id)initWithProperty:(PropertyType *)prop
{
if(self = [super init]) {
_prop = prop;
[_prop doSomething];
}
return self;
}
#end
Rectangle.m/Circle.m
#implementation Rectangle
- (void)initWithRect:(CGRect)rect
{
return [self initWithProperty:[RectangleStuff rectangleWithRect:rect]];
}
#end
#implementation Circle
- (void)initWithRadius:(CGFloat)radius
{
return [self initWithProperty:[CircleStuff circleWithRadius:radius]];
}
#end
This a very basic question but I've searched all over and been unable to find an answer that explains well enough for me to get my head around it.
What I want to do is create a method in one class of my iOS app and then call that method from other classes in my app. Could someone explain exactly what I need to do to achieve this? Any help would be greatly appreciated as all my attempts so far have failed!
Thanks.
Objective-C:
You have to import the header of the class that contains the method you want to use (ClassYouWantToUse.h) into the class you want to use it at (TargetClass).
Inside the TargetClass.h or TargetClass.m (depending on the scope you want to give it):
#import "ClassYouWantToUse.h"
Then create an instance of the class you want to use inside the target class either as a property like this:
#property (nonatomic,strong) ClassYouWantToUse *classObject;
Or as an instance variable like this:
ClassYouWantToUse *classObject;
Make sure you initialize it! (usually inside ViewDidLoad):
classObject = [[ClassYouWantToUse alloc] init];
Now you can call any public methods from that class like this:
[classObject theClassMethodWithParam:param1 andSecondParam:param2];
Note: The ClassYouWantToUse class must have the methods that you want to make accessible to others by declaring them in the header file:
- (void)theClassMethodWithParam:(UIImage*)someImage andSecondParam:(NSString*)someText;
Otherwise you won't be able to see these methods.
Swift:
Theres really nothing special about it in swift, just adding this as a reference.
In swift you simply create an instance of the class you want to use:
let classObject = ClassYouWantToUse()
And use it directly:
classObject.theClassMethodWithParam(param1, andSecondParam:param2)
You have two basic options. You can either create or pass-in an instance of the first class to the second class, or you can add a static method to the first class and call it directly using the class object.
For instance, say you have:
#interface ClassA : NSObject {
}
//instance methods
- (int) addNumber:(int)num1 withNumber:(int)num2;
//static/class methods
+ (int) add:(int)num1 with:(int)num2;
#end
#implementation ClassA
- (int) addNumber:(int)num1 withNumber:(int)num2 {
return num1 + num2;
}
+ (int) add:(int)num1 with:(int)num2 {
return num1 + num2;
}
#end
Then you can do:
#import "ClassA.h"
#interface ClassB : NSObject {
ClassA* adder;
}
//constructors
- (id) init; //creates a new instance of ClassA to use
- (id) initWithAdder:(ClassA*)theAdder; //uses the provided instance of ClassA
//instance methods
- (int) add2To:(int)num;
//static/class methods
+ (int) add3To:(int)num;
#end
#implementation ClassB
- (id) init {
if (self = [super init]) {
adder = [[ClassA alloc] init];
}
return self;
}
- (id) initWithAdder:(ClassA*)theAdder {
if (self = [super init]) {
adder = theAdder;
}
return self;
}
- (int) add2To:(int)num {
return [adder addNumber:2 withNumber:num];
}
+ (int) add3To:(int)num {
return [ClassA add:3 with:num];
}
#end
Note that in most cases, you would use instance methods rather than static methods.
You have to use the concept of delegation.
https://developer.apple.com/library/ios/#documentation/General/Conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources.html