1. dynamically add attributes to the NSObject class
H Definition
[Cpp]
@ Interface UIWebView (LoadProgress)
@ Property (nonatomic, assign) NSInteger resourceCount;
@ End
@ Interface UIWebView (LoadProgress)
@ Property (nonatomic, assign) NSInteger resourceCount;
@ End
M implementation
First, define a global key.
[Cpp]
// ResourceCount object keys
Static void * s_resourceCountKey = & s_resourceCountKey;
// Static void * s_resourceCountKey = "s_resourceCountKey ";
// ResourceCount object keys
Static void * s_resourceCountKey = & s_resourceCountKey;
// Static void * s_resourceCountKey = "s_resourceCountKey ";
Initial
[Cpp]
@ Implementation UIWebView (LoadProgress)
@ Dynamic resourceCount;
@ Implementation UIWebView (LoadProgress)
@ Dynamic resourceCount;
Implementation
[Cpp]
# Pragma mark Accessors and mutators
-(NSInteger) resourceCount
{
NSNumber * resourceCountNumber = objc_getAssociatedObject (self, s_resourceCountKey );
If (! ResourceCountNumber)
{
Return 0;
}
Else
{
Return [resourceCountNumber integerValue];
}
}
-(Void) setResourceCount :( NSInteger) rCount
{
Objc_setAssociatedObject (self, s_resourceCountKey, [NSNumber numberWithInteger: rCount], OBJC_ASSOCIATION_RETAIN_NONATOMIC );
}
# Pragma mark Accessors and mutators
-(NSInteger) resourceCount
{
NSNumber * resourceCountNumber = objc_getAssociatedObject (self, s_resourceCountKey );
If (! ResourceCountNumber)
{
Return 0;
}
Else
{
Return [resourceCountNumber integerValue];
}
}
-(Void) setResourceCount :( NSInteger) rCount
{
Objc_setAssociatedObject (self, s_resourceCountKey, [NSNumber numberWithInteger: rCount], OBJC_ASSOCIATION_RETAIN_NONATOMIC );
}
In this way, you can use it directly.
WebView. resourceCount = 10;
2. dynamically Add a proxy protocol to the NSObject class
Same attribute
No more proxies are created.
3. replace or change the NSObject Class Method
Basic replacement method
[Cpp]
// Replacement Class Method
// Frome: CoconutKit
IMP HLSSwizzleClassSelector (Class clazz, SEL selector, IMP newImplementation)
{
// Get the original implementation we are replacing
Class metaClass = objc_getMetaClass (class_getName (clazz ));
Method method = class_getClassMethod (metaClass, selector );
IMP origImp = method_getImplementation (method );
If (! OrigImp ){
Return NULL;
}
Class_replaceMethod (metaClass, selector, newImplementation, method_getTypeEncoding (method ));
Return origImp;
}
// Instance replacement method
IMP HLSSwizzleSelector (Class clazz, SEL selector, IMP newImplementation)
{
// Get the original implementation we are replacing
Method method = class_getInstanceMethod (clazz, selector );
IMP origImp = method_getImplementation (method );
If (! OrigImp ){
Return NULL;
}
Class_replaceMethod (clazz, selector, newImplementation, method_getTypeEncoding (method ));
Return origImp;
}
// Replacement Class Method
// Frome: CoconutKit
IMP HLSSwizzleClassSelector (Class clazz, SEL selector, IMP newImplementation)
{
// Get the original implementation we are replacing
Class metaClass = objc_getMetaClass (class_getName (clazz ));
Method method = class_getClassMethod (metaClass, selector );
IMP origImp = method_getImplementation (method );
If (! OrigImp ){
Return NULL;
}
Class_replaceMethod (metaClass, selector, newImplementation, method_getTypeEncoding (method ));
Return origImp;
}
// Instance replacement method
IMP HLSSwizzleSelector (Class clazz, SEL selector, IMP newImplementation)
{
// Get the original implementation we are replacing
Method method = class_getInstanceMethod (clazz, selector );
IMP origImp = method_getImplementation (method );
If (! OrigImp ){
Return NULL;
}
Class_replaceMethod (clazz, selector, newImplementation, method_getTypeEncoding (method ));
Return origImp;
}
New method definition
[Cpp]
// Original implementation of the methods we swizzle
Static id (* s_UIWebView _ identifierForInitialRequest_Imp) (id, SEL, id) = NULL;
// Swizzled method implementations
Static id swizzled_UIWebView _ identifierForInitialRequest_Imp (UIWebView * self, SEL _ cmd, id webView, id initialRequest, id dataSource );
// Original implementation of the methods we swizzle
Static id (* s_UIWebView _ identifierForInitialRequest_Imp) (id, SEL, id) = NULL;
// Swizzled method implementations
Static id swizzled_UIWebView _ identifierForInitialRequest_Imp (UIWebView * self, SEL _ cmd, id webView, id initialRequest, id dataSource );
Method initialization needs to be written in class method + (void) load
[Cpp]
+ (Void) load
{
S_UIWebView _ identifierForInitialRequest_Imp = (id (*) (id, SEL, id) HLSSwizzleSelector (self, @ selector (webView: identifierForInitialRequest: fromDataSource :), (IMP) swizzled_UIWebView _ identifierForInitialRequest_Imp );
}
+ (Void) load
{
S_UIWebView _ identifierForInitialRequest_Imp = (id (*) (id, SEL, id) HLSSwizzleSelector (self, @ selector (webView: identifierForInitialRequest: fromDataSource :), (IMP) swizzled_UIWebView _ identifierForInitialRequest_Imp );
}
Implementation
[Cpp]
# Pragma mark Swizzled method implementations
Static id swizzled_UIWebView _ identifierForInitialRequest_Imp (UIWebView * self, SEL _ cmd, id webView, id initialRequest, id dataSource)
{
// Call the original method
(* S_UIWebView _ identifierForInitialRequest_Imp) (self, _ cmd, webView, initialRequest, dataSource );
[Self setResourceCount: self. resourceCount + 1];
Return [NSNumber numberWithInteger: self. resourceCount];
}
# Pragma mark Swizzled method implementations
Static id swizzled_UIWebView _ identifierForInitialRequest_Imp (UIWebView * self, SEL _ cmd, id webView, id initialRequest, id dataSource)
{
// Call the original method
(* S_UIWebView _ identifierForInitialRequest_Imp) (self, _ cmd, webView, initialRequest, dataSource );
[Self setResourceCount: self. resourceCount + 1];
Return [NSNumber numberWithInteger: self. resourceCount];
}
4. Proxy method Retrieval
Can be directly defined in the NSObject Category
[Cpp]
// [Self implementsProtocol: @ protocol (UIActionSheetDelegate)]
// [Self implementsProtocol: @ protocol (UIActionSheetDelegate)] [cpp] view plaincopyprint?
// Frome: CoconutKit
-(BOOL) implementsProtocol :( Protocol *) protocol
{
// Only interested in optional methods. Required methods are checked at compilation time
Unsigned int numberOfMethods = 0;
Struct objc_method_description * methodDescriptions = protocol_copyMethodDescriptionList (protocol, NO/* optional only */, YES, & numberOfMethods );
For (unsigned int I = 0; I <numberOfMethods; ++ I ){
Struct objc_method_description methodDescription = methodDescriptions [I];
SEL selector = methodDescription. name;
If (! Class_getInstanceMethod ([self class], selector )){
NSString * selectorString = [NSString stringWithCString: sel_getName (selector) encoding: NSUTF8StringEncoding];
NSString * protocolName = [NSString stringWithCString: protocol_getName (protocol) encoding: NSUTF8StringEncoding];
HLSLoggerInfo (@ "Class % @ does not implement method % @ of protocol % @", [self className], selectorString, protocolName );
SelectorString = nil; // Just to remove unused variable warnings
ProtocolName = nil;
Return NO;
}
}
Return YES;
}
// Frome: CoconutKit
-(BOOL) implementsProtocol :( Protocol *) protocol
{
// Only interested in optional methods. Required methods are checked at compilation time
Unsigned int numberOfMethods = 0;
Struct objc_method_description * methodDescriptions = protocol_copyMethodDescriptionList (protocol, NO/* optional only */, YES, & numberOfMethods );
For (unsigned int I = 0; I <numberOfMethods; ++ I ){
Struct objc_method_description methodDescription = methodDescriptions [I];
SEL selector = methodDescription. name;
If (! Class_getInstanceMethod ([self class], selector )){
NSString * selectorString = [NSString stringWithCString: sel_getName (selector) encoding: NSUTF8StringEncoding];
NSString * protocolName = [NSString stringWithCString: protocol_getName (protocol) encoding: NSUTF8StringEncoding];
HLSLoggerInfo (@ "Class % @ does not implement method % @ of protocol % @", [self className], selectorString, protocolName );
SelectorString = nil; // Just to remove unused variable warnings
ProtocolName = nil;
Return NO;
}
}
Return YES;
}