SEL
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
OBJC_EXPORT const char *sel_getName(SEL sel)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT SEL sel_registerName(const char *str)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT SEL sel_getUid(const char *str)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT BOOL sel_isMapped(SEL sel)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT BOOL sel_isEqual(SEL lhs, SEL rhs)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
SEL应用
- (void)use_sel
{
SEL sel1 = @selector(feedRice:andMeat:);
SEL sel2 = @selector(feedRice:andMeat:);
SEL sel3 = sel_registerName("feedRice:andMeat:");
SEL sel4 = @selector(feedFruit:andFish:);
SEL sel5 = @selector(feedFruit:andFish:);
SEL sel6 = sel_registerName("feedFruit:andFish:");
NSLog(@"sel1 = %p, sel2 = %p, sel3 = %p", sel1, sel2, sel3);
NSLog(@"sel4 = %p, sel5 = %p, sel6 = %p", sel4, sel5, sel6);
NSLog(@"%d, %d", sel1 == sel2, sel1 == sel4);
NSLog(@"%d, %d", sel_isEqual(sel1, sel2), sel_isEqual(sel1, sel4));
NSLog(@"%d, %d", sel_isMapped(sel1), sel_isMapped(sel4));
}
output:
sel1 = 0x1087314c7, sel2 = 0x1087314c7, sel3 = 0x1087314c7
sel4 = 0x1087314d9, sel5 = 0x1087314d9, sel6 = 0x1087314d9
1, 0
1, 0
1, 1
SEL总结
- runtime system维护着SEL的dictionary,key为SEL对应字符串,value为SEL
- @selector,sel_registerName,sel_getUid等同,根据字符串从SEL dictionary search SEL,如果found,返回SEL,如果not found,创建后返回
- sel_isEqual同==
- sel_isMapped判断SEL是否存在SEL dictionary中
Method
/// Defines a method
struct objc_method_description {
SEL name; /**< The name of the method */
char *types; /**< The types of the method arguments */
};
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
char *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id (*IMP)(id, SEL, ...);
#endif
/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;
OBJC_EXPORT SEL method_getName(Method m)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT IMP method_getImplementation(Method m)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT const char *method_getTypeEncoding(Method m)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT char *method_copyReturnType(Method m)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT char *method_copyArgumentType(Method m, unsigned int index)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT void method_getReturnType(Method m, char *dst, size_t dst_len)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT unsigned int method_getNumberOfArguments(Method m)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT void method_getArgumentType(Method m, unsigned int index,
char *dst, size_t dst_len)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT struct objc_method_description *method_getDescription(Method m)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT IMP method_setImplementation(Method m, IMP imp)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
Method应用
@interface FBMeat : NSObject
@end
@implementation FBMeat
@end
@interface FBAnimal : NSObject
- (void)feedRice:(int)rice andMeat:(FBMeat *)meat;
- (UIColor*)getColor:(int)cIndex;
@end
@implementation FBAnimal
- (void)feedRice:(int)rice andMeat:(FBMeat *)meat
{
}
- (UIColor*)getColor:(int)cIndex
{
return [UIColor purpleColor];
}
@end
- (void)use_method
{
{
Method method = class_getInstanceMethod([FBAnimal class], @selector(feedRice:andMeat:));
NSLog(@"-----feedRice:andMeat:-----");
NSLog(@"type encoding = %s", method_getTypeEncoding(method));
char* retType = method_copyReturnType(method);
NSLog(@"ret type = %s", retType);
free(retType);
int argNum = method_getNumberOfArguments(method);
NSLog(@"arg num = %d", argNum);
for(int i = 0; i < argNum; ++i)
{
char *argType = method_copyArgumentType(method, i);
NSLog(@"arg %d type = %s", i, argType);
free(argType);
}
}
{
Method method = class_getInstanceMethod([FBAnimal class], @selector(getColor:));
NSLog(@"-----getColor:-----");
NSLog(@"type encoding = %s", method_getTypeEncoding(method));
char* retType = method_copyReturnType(method);
NSLog(@"ret type = %s", retType);
free(retType);
int argNum = method_getNumberOfArguments(method);
NSLog(@"arg num = %d", argNum);
for(int i = 0; i < argNum; ++i)
{
char *argType = method_copyArgumentType(method, i);
NSLog(@"arg %d type = %s", i, argType);
free(argType);
}
}
}
output:
-----feedRice:andMeat:-----
type encoding = v28@0:8i16@20
ret type = v
arg num = 4
arg 0 type = @
arg 1 type = :
arg 2 type = i
arg 3 type = @
-----getColor:-----
type encoding = @20@0:8i16
ret type = @
arg num = 3
arg 0 type = @
arg 1 type = :
arg 2 type = i
Method总结
- 类的方法(instance method和class method)类型本质为IMP类型,因此类的方法(instance method和class method)参数个数为IMP类型参数个数,即包含id和SEL
api
struct objc_method_list {
struct objc_method_list *obsolete OBJC2_UNAVAILABLE;
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp,
const char *types)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT Method class_getInstanceMethod(Class cls, SEL name)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT Method class_getClassMethod(Class cls, SEL name)
__OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
OBJC_EXPORT Method *class_copyMethodList(Class cls, unsigned int *outCount)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT IMP class_replaceMethod(Class cls, SEL name, IMP imp,
const char *types)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT IMP class_getMethodImplementation(Class cls, SEL name)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
OBJC_EXPORT IMP class_getMethodImplementation_stret(Class cls, SEL name)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0)
OBJC_ARM64_UNAVAILABLE;
OBJC_EXPORT BOOL class_respondsToSelector(Class cls, SEL sel)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
应用
@interface FBAnimal : NSObject
- (void)feedFood1:(int)food1 andFood2:(int)food2;
- (void)feedFood3:(int)food3 andFood4:(int)food4;
@end
@implementation FBAnimal
- (void)feedFood3:(int)food3 andFood4:(int)food4
{
}
- (void)feedFood1:(int)food1 andFood2:(int)food2
{
}
@end
@interface FBAnimal (FeedFood56)
- (void)feedFood3:(int)food3 andFood4:(int)food4;
- (void)feedFood5:(int)food5 andFood6:(int)food6;
@end
@implementation FBAnimal (FeedFood56)
- (void)feedFood3:(int)food3 andFood4:(int)food4;
{
}
- (void)feedFood5:(int)food5 andFood6:(int)food6
{
}
@end
@interface FBAnimal (FeedFood78)
- (void)feedFood3:(int)food3 andFood4:(int)food4;
- (void)feedFood7:(int)food7 andFood8:(int)food8;
@end
@implementation FBAnimal (FeedFood78)
- (void)feedFood3:(int)food3 andFood4:(int)food4;
{
}
- (void)feedFood7:(int)food7 andFood8:(int)food8
{
}
@end
@interface FBDog : FBAnimal
- (void)bark:(int)vol;
- (void)attack:(int)hurt;
@end
@implementation FBDog
- (void)bark:(int)vol
{
}
- (void)attack:(int)hurt
{
}
@end
- (void)class_methodLists
{
Method method = class_getInstanceMethod([FBDog class], @selector(feedFood3:andFood4:));
NSLog(@"method name = %s, method type = %s", sel_getName(method_getName(method)), method_getTypeEncoding(method));
NSLog(@"respondsToSelector: %d", class_respondsToSelector([FBDog class], @selector(feedFood3:andFood4:)));
NSLog(@"animal method list:");
unsigned int animalMethodCnt = 0;
Method* animalMethodList = class_copyMethodList([FBAnimal class], &animalMethodCnt);
for(int i = 0; i < animalMethodCnt; ++i)
{
Method thisMethod = animalMethodList[i];
NSLog(@"method name = %s, method type = %s", sel_getName(method_getName(thisMethod)), method_getTypeEncoding(thisMethod));
}
free(animalMethodList);
NSLog(@"dog method list:");
unsigned int dogMethodCnt = 0;
Method* dogMethodList = class_copyMethodList([FBDog class], &dogMethodCnt);
for(int i = 0; i < dogMethodCnt; ++i)
{
Method thisMethod = dogMethodList[i];
NSLog(@"method name = %s, method type = %s", sel_getName(method_getName(thisMethod)), method_getTypeEncoding(thisMethod));
}
free(dogMethodList);
}
output:
method name = feedFood3:andFood4:, method type = v24@0:8i16i20
respondsToSelector: 1
animal method list:
method name = feedFood3:andFood4:, method type = v24@0:8i16i20
method name = feedFood3:andFood4:, method type = v24@0:8i16i20
method name = feedFood3:andFood4:, method type = v24@0:8i16i20
method name = feedFood1:andFood2:, method type = v24@0:8i16i20
method name = feedFood5:andFood6:, method type = v24@0:8i16i20
method name = feedFood7:andFood8:, method type = v24@0:8i16i20
dog method list:
method name = bark:, method type = v20@0:8i16
method name = attack:, method type = v20@0:8i16
总结
- 如果类中已含对应SEL的Method,class_addMethod不会添加到当前类中
- 如果类中已含对应SEL的Method,class_replaceMethod等同于method_setImplementation,参数types ignored,如果类中不含对应SEL的Method,class_replaceMethod等同于class_addMethod
- class_getInstanceMethod(class object)和class_getClassMethod(meta-class object)包含super_class
- class_respondsToSelector包含super_class
- class_copyIvarList不包含super_class
- 继承体系方法成员排列顺序:父类->子类
- 同一类方法成员排列顺序:primary class implementation->category implementation
- 同一类多个category方法成员排列顺序:按category编译顺序排列,即先编译category排前面,后编译category排后面
- 同一implementation(rimary class implementation,category implementation)方法成员排列顺序:按方法成员编译顺序排列,即先编译方法成员排前面,后编译方法成员排后面
- 如果primary class implementation与category implementation方法成员重复,这些重复方法成员排列在一起,顺序按照primary class implementation->category implementation,如果多个category方法成员重复,按category编译顺序排列,即先编译category排前面,后编译category排后面