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
Related
The project I'm working on is a mix of Swift and Objective-C. Here's the snippet:
// ViewController.m
#interface ViewController ()
#property (nonatomic, strong) MyModel *model;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.model = [[MyModel alloc] initWithIntValue:10];
}
// MyModel.swift
fileprivate class SomeProperty {
init() {
print("SomeProperty init")
}
}
class MyModel: BaseModel {
private let property = SomeProperty()
}
// BaseModel.h
#interface BaseModel : NSObject
- (instancetype)initWithIntValue:(int)intValue;
- (instancetype)initWithIntValue:(int)intValue doubleValue:(double)doubleValue;
#end
// BaseModel.m
#implementation BaseModel
- (instancetype)initWithIntValue:(int)intValue doubleValue:(double)doubleValue {
if (self = [super init]) {
}
return self;
}
- (instancetype)initWithIntValue:(int)intValue {
return [self initWithIntValue:intValue doubleValue:0];
}
#end
Interestingly, I find when MyModel instance is initialized, SomeProperty init will be printed twice, which means two SomeProperty instances are created. What's worse, Debug Memory Graph shows that there is a SomeProperty object memory leak. So why is this and how can I fix it?
Rewrite BaseModel.h like this:
- (instancetype)initWithIntValue:(int)intValue;
- (instancetype)initWithIntValue:(int)intValue doubleValue:(double)doubleValue NS_DESIGNATED_INITIALIZER;
Note the NS_DESIGNATED_INITIALIZER marker at the end of the second initializer. (You may have to scroll my code in order to see it.)
This marker, aside from what it does within Objective-C (in its role as a macro), tells Swift that both initializers are not designated initializers; rather, Swift concludes, the first one is a convenience initializer. And that is correct; it calls another initializer, namely — in this case — the designated initializer.
Without that NS_DESIGNATED_INITIALIZER markup, Swift interprets the situation incorrectly because of the (already rather complicated) relationship between Swift initializers and Objective-C initializers. It thinks both initializers are designated initializers and you get this curious double initialization from Swift.
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 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
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 question already has answers here:
Difference between #interface definition in .h and .m file
(3 answers)
Closed 10 years ago.
Sometimes I see another interface declaration like this:
#interface MyCode ()
#end
Isn't this duplicating the one in the .h file?
That is a category provided by Xcode and is used to declare private properties and methods that are only usable from within this implementation file.
You won't always want to expose all of the methods from your class to the outside world, and instead you would declare them in this private category (I always prefix these private methods with an underscore (_) to make it obvious I am calling a private method, but that is entirely optional).
As an example, here is a private intialization method that I don't want exposed:
#interface MyClass ()
- (BOOL)_init;
#end
#implementation MyClass
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
if (![self _init])
self = nil;
}
return self;
}
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:code];
if (self != nil)
{
if (![self _init])
self = nil;
}
return self;
}
- (BOOL)_init
{
self.something = whatnot;
self.thingA = self.thingB;
return YES;
}
it is used when you want to declare private ivars/properties/methods.
In .h file you've got public methods and properties, and in .m file you have private.
The concept is that you can make your project much cleaner if you limit the .h to the public interfaces of your class, and then put private implementation details in this class extension. See the discussion of private class extensions in the Programming with Objective-C guide.
This #Interface allows you to declare private ivars, properties and methods. So anything you declare here cannot be accessed from outside this class. In general, you want to declare all ivars, properties and methods by default as private (in this #interface()) unless an instance of the class needs to access them.
Hope this helps
It's a class extension. Read more
Usually used for declaration private ivars/properties/methods.