iOS---学习研究大牛Git高星项目YYCategories(二)

 
 
三、YYCategoriesMacro.h
一个宏定义类,我会把这一块的功能说一下。
tip1:
Q : 在项目的 .h 文件中,
#ifndef XXX_h
#define XXX_h
//程序段1
#endif  /* XXX_h */
的作用?

A : 如果 XXX.h 不存在,就引入 XXX.h ,否则不用引入. 是为了防止该文件被重复引用.

#什么是重复引用:
其实“被重复引用”是指一个头文件在同一个cpp文件中被include了多次,这种错误常常是由于include嵌套造成的。比如:存在a.h文件#include "c.h"而此时b.cpp文件导入了#include "a.h" 和#include "c.h"此时就会造成c.h重复引用。

#头文件被重复引用引起的后果:
有些头文件重复引用只是增加了编译工作的工作量,不会引起太大的问题,仅仅是编译效率低一些,但是对于大工程而言编译效率低下那将是一件多么痛苦的事情。
有些头文件重复包含,会引起错误,比如在头文件中定义了全局变量(虽然这种方式不被推荐,但确实是C规范允许的)这种会引起重复定义。
 扩展:
Q : #if , #ifdef , #ifndef 的使用方法?

A : #1,#2,#3.

#1
#if condition(表达式1)
//程序段1
(#elif condition(表达式n)
//程序段n
)
...
(#else
//程序段3
)
#endif
说明 : 如果 表达式1(condition : true),则执行 程序段1,(否则如果 表达式2(condition : true),则执行 程序段n),(否则执行 程序段3).

#2
#ifdef macro(标识符1)
//程序段1
(#else
//程序段2
)
#endif
说明 : 如果 有定义标识符1(#define macro),则执行 程序段1,(否则执行 程序段2).

#3
#ifndef macro(标识符1)
//程序段1
(#else
//程序段2
)
#endif
说明 : 如果 没有定义标识符1(#define macro),则执行 程序段1,(否则执行 程序段2).与#2相反!

详细请看:Objective-C预编译处理

tip2:

#ifdef __cplusplus
#define YY_EXTERN_C_BEGIN  extern "C" {

#define YY_EXTERN_C_END  }
#else
#define YY_EXTERN_C_BEGIN

#define YY_EXTERN_C_END

/*
功能

在C++环境中有定义 __cplusplus 这个宏,如果在C++环境中, YY_EXTERN_C_BEGIN和 YY_EXTERN_C_END中间的代码,编译器用C语言的编译格式来编译.因为 C++ 为了实现函数重载会把函数名和参数等联合起来合成一个中介的函数名,如果 C 函数也被这样编译会出问题.

*/

tip3:

/**
 Add this macro before each category implementation, so we don't have to use
 -all_load or -force_load to load object files from static libraries that only
 contain categories and no classes.
 More info: http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html .
 *******************************************************************************
 Example:
     YYSYNTH_DUMMY_CLASS(NSString_YYAdd)
 */
#ifndef YYSYNTH_DUMMY_CLASS
#define YYSYNTH_DUMMY_CLASS(_name_) 
@interface YYSYNTH_DUMMY_CLASS_ ## _name_ : NSObject @end 
@implementation YYSYNTH_DUMMY_CLASS_ ## _name_ @end
#endif

这个宏定义的功能上面已经讲得很清楚了。在每个类别实现之前添加这个宏,这样我们就不必使用-all_load或-force_load来从只包含类别而不包含类的静态库加载对象文件。

在用第三方库、类或者静态库时,我们常常在Xcode的Build Settings下Other Linker Flags里面加入-ObjC标志。

原因:

Unix的标准静态库实现和Objective-C的动态特性之间有一些冲突:Objective-C没有为每个函数(或者方法)定义链接符号,它只为每个类创建链接符号。这样当在一个静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时,出现"selector not recognized",也就是找不到方法定义的错误。为了解决这个问题,引入了-ObjC标志,它的作用就是将静态库中所有的和对象相关的文件都加载进来。

不要以为这样就可以解决所有问题了,在64位的Mac系统或者iOS系统下,链接器有一个bug,会导致只包含有类别的静态库无法使用-ObjC标志来加载文件。变通方法是使用-all_load 或者-force_load标志,它们的作用都是加载静态库中所有文件,不过all_load作用于所有的库,而-force_load后面必须要指定具体的文件他们加载的位置也是在Xcode的Build Settings下Other Linker Flags里面。

所以一般加了这两个的都是存在一些扩展类。

只要加入了这个宏定义我们就不需要在添加这两个方法了。

使用方法:
YYSYNTH_DUMMY_CLASS(NSArray_YYAdd)

tip4:

/**
 Synthsize a dynamic object property in @implementation scope.
 It allows us to add custom properties to existing classes in categories.
 
 @param association  ASSIGN / RETAIN / COPY / RETAIN_NONATOMIC / COPY_NONATOMIC
 @warning #import <objc/runtime.h>
 *******************************************************************************
 Example:
     @interface NSObject (MyAdd)
     @property (nonatomic, retain) UIColor *myColor;
     @end
     
     #import <objc/runtime.h>
     @implementation NSObject (MyAdd)
     YYSYNTH_DYNAMIC_PROPERTY_OBJECT(myColor, setMyColor, RETAIN, UIColor *)
     @end
 */
#ifndef YYSYNTH_DYNAMIC_PROPERTY_OBJECT
#define YYSYNTH_DYNAMIC_PROPERTY_OBJECT(_getter_, _setter_, _association_, _type_) 
- (void)_setter_ : (_type_)object { 
    [self willChangeValueForKey:@#_getter_]; 
    objc_setAssociatedObject(self, _cmd, object, OBJC_ASSOCIATION_ ## _association_); 
    [self didChangeValueForKey:@#_getter_]; 
} 
- (_type_)_getter_ { 
    return objc_getAssociatedObject(self, @selector(_setter_:)); 
}
#endif

这是一个给category 动态添加属性的宏。

使用方法:

.h中
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

#ifndef YYSYNTH_DYNAMIC_PROPERTY_OBJECT
#define YYSYNTH_DYNAMIC_PROPERTY_OBJECT(_getter_, _setter_, _association_, _type_) 
- (void)_setter_ : (_type_)object { 
[self willChangeValueForKey:@#_getter_]; 
objc_setAssociatedObject(self, _cmd, object, OBJC_ASSOCIATION_ ## _association_); 
[self didChangeValueForKey:@#_getter_]; 
} 
- (_type_)_getter_ { 
return objc_getAssociatedObject(self, @selector(_setter_:)); 
}
#endif

@interface NSObject (MyAdd)

@property (nonatomic, retain) NSString *myName;

@end


.m中
#import "NSObject+MyAdd.h"
#import <objc/runtime.h>

@implementation NSObject (MyAdd)

YYSYNTH_DYNAMIC_PROPERTY_OBJECT(myName, setMyName, RETAIN, NSString *);

@end

效果如图 

这样就可以为扩展类添加属性了。

参考链接:学习yykit 一些小小总结

tip5:

/**
 Synthsize a dynamic c type property in @implementation scope.
 It allows us to add custom properties to existing classes in categories.
 
 @warning #import <objc/runtime.h>
 *******************************************************************************
 Example:
     @interface NSObject (MyAdd)
     @property (nonatomic, retain) CGPoint myPoint;
     @end
     
     #import <objc/runtime.h>
     @implementation NSObject (MyAdd)
     YYSYNTH_DYNAMIC_PROPERTY_CTYPE(myPoint, setMyPoint, CGPoint)
     @end
 */
#ifndef YYSYNTH_DYNAMIC_PROPERTY_CTYPE
#define YYSYNTH_DYNAMIC_PROPERTY_CTYPE(_getter_, _setter_, _type_) 
- (void)_setter_ : (_type_)object { 
    [self willChangeValueForKey:@#_getter_]; 
    NSValue *value = [NSValue value:&object withObjCType:@encode(_type_)]; 
    objc_setAssociatedObject(self, _cmd, value, OBJC_ASSOCIATION_RETAIN); 
    [self didChangeValueForKey:@#_getter_]; 
} 
- (type)_getter_ { 
    _type_ cValue = { 0 }; 
    NSValue *value = objc_getAssociatedObject(self, @selector(_setter_:)); 
    [value getValue:&cValue]; 
    return cValue; 
}
#endif

这是一个添加c类型属性的宏。和上面类似。

原文地址:https://www.cnblogs.com/weicyNo-1/p/9208872.html