结语

# 开篇

1




# 文件包含

## #import

OC特有的就是一个智能的#include，解决了#include的重复包含的问题。

# 宏定义

## 宏定义的黑魔法 - 宏菜鸟起飞手册

### 入门


//This defines PI
#define M_PI        3.14159265358979323846264338327950288

#define关键字表明即将开始定义一个宏，紧接着的M_PI是宏的名字，空格之后的数字是内容。类似这样的#define X A的宏是比较简单的，在编译时编译器会在语义分析认定是宏后，将X替换为A，这个过程称为宏的展开。比如对于上面的M_PI


#define M_PI        3.14159265358979323846264338327950288

double r = 10.0;
double circlePerimeter = 2 * M_PI * r;
// => double circlePerimeter = 2 * 3.14159265358979323846264338327950288 * r;

printf("Pi is %0.7f",M_PI);
//Pi is 3.1415927


//A simple function-like macro
#define SELF(x)      x
NSString *name = @"Macro Rookie";
NSLog(@"Hello %@",SELF(name));
// => NSLog(@"Hello %@",name);
//   => Hello Macro Rookie


#define PLUS(x,y) x + y
printf("%d",PLUS(3,2));
// => printf("%d",3 + 2);
//  => 5

### 宏的世界，小有乾坤


//Version 1.0
#define MIN(A,B) A < B ? A : B

Try一下


int a = MIN(1,2);
// => int a = 1 < 2 ? 1 : 2;
printf("%d",a);
// => 1


int a = 2 * MIN(3, 4);
printf("%d",a);
// => 4


int a = 2 * MIN(3, 4);
// => int a = 2 * 3 < 4 ? 3 : 4;
// => int a = 6 < 4 ? 3 : 4;
// => int a = 4;


//Version 2.0
#define MIN(A,B) (A < B ? A : B)


int a = MIN(3, 4 < 5 ? 4 : 5);
printf("%d",a);
// => 4


int a = MIN(3, 4 < 5 ? 4 : 5);
// => int a = (3 < 4 < 5 ? 4 : 5 ? 3 : 4 < 5 ? 4 : 5);  //希望你还记得运算符优先级
//  => int a = ((3 < (4 < 5 ? 4 : 5) ? 3 : 4) < 5 ? 4 : 5);  //为了您不太纠结，我给这个式子加上了括号
//   => int a = ((3 < 4 ? 3 : 4) < 5 ? 4 : 5)
//    => int a = (3 < 5 ? 4 : 5)
//     => int a = 4


//Version 3.0
#define MIN(A,B) ((A) < (B) ? (A) : (B))


float a = 1.0f;
float b = MIN(a++, 1.5f);
printf("a=%f, b=%f",a,b);
// => a=3.000000, b=2.000000


float a = 1.0f;
float b = MIN(a++, 1.5f);
// => float b = ((a++) < (1.5f) ? (a++) : (1.5f))


int a = ({
int b = 1;
int c = 2;
b + c;
});
// => a is 3


//GNUC MIN
#define MIN(A,B)    ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })


//CLANG MIN
#define __NSX_PASTE__(A,B) A##B

#define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)

#define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); })




#define __NSX_PASTE__(A,B) A##B

#define MIN(A,B) __NSMIN_IMPL__(A,B,__COUNTER__)

#define __NSMIN_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); \
__typeof__(B) __NSX_PASTE__(__b,L) = (B); \
(__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__a,L) : __NSX_PASTE__(__b,L); \
})



### Log，永恒的主题

Log人人爱，它为我们指明前进方向，它为我们抓虫提供帮助。在objc中，我们最多使用的log方法就是NSLog输出信息到控制台了，但是NSLog的标准输出可谓残废，有用信息完全不够，比如下面这段代码：

NSArray *array = @[@"Hello", @"My", @"Macro"];
NSLog (@"The array is %@", array); 

2014-01-20 11:22:11.835 TestProject[23061:70b] The arr

ay is ( Hello, My, Macro )

//A better version of NSLog
#define NSLog(format, ...) do {                                                                          \
fprintf(stderr, "<%s : %d> %s\n",                                           \
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],  \
__LINE__, __func__);                                                        \
(NSLog)((format), ##__VA_ARGS__);                                           \
fprintf(stderr, "-------\n");                                               \
} while (0)

//A wrong version of NSLog
#define NSLog(format, ...)   fprintf(stderr, "<%s : %d> %s\n",                                           \
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],  \
__LINE__, __func__);                                                        \
(NSLog)((format), ##__VA_ARGS__);                                           \
fprintf(stderr, "-------\n"); 

if (errorHappend)
NSLog(@"Oops, error happened");

if (errorHappend)
fprintf((stderr, "<%s : %d> %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((format), ##__VA_ARGS__); //I wi

ll expand this later fprintf(stderr, "-------\n");

//Another wrong version of NSLog
#define NSLog(format, ...)   {
fprintf(stderr, "<%s : %d> %s\n",                                           \
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],  \
__LINE__, __func__);                                                        \
(NSLog)((format), ##__VA_ARGS__);                                           \
fprintf(stderr, "-------\n");                                               \
}

//I am sorry if you don't like { in the same like. But I am a fan of this style :P
if (errorHappend) {
fprintf((stderr, "<%s : %d> %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((format), ##__VA_ARGS__);
fprintf(stderr, "-------\n");
};

if (errorHappend)
NSLog(@"Oops, error happened");
else
//Yep, no error, I am happy~ :)

No! I am not haapy at all! 因为编译错误了！实际上这个宏展开以



if (errorHappend) {
fprintf((stderr, "<%s : %d> %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((format), ##__VA_ARGS__);
fprintf(stderr, "-------\n");
}; else {
//Yep, no error, I am happy~ :)
}



if (errorHappend)
do {
fprintf((stderr, "<%s : %d> %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((format), ##__VA_ARGS__);
fprintf(stderr, "-------\n");
} while (0);
else {
//Yep, no error, I am really happy~ :)
}



[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);



-------
<AppDelegate.m : 46> -[AppDelegate application:didFinishLaunchingWithOptions:]
2014-01-20 16:44:25.480 TestProject[30466:70b] The array is (
Hello,
My,
Macro
)
-------



NSLog(@"Hello");
=> do {
fprintf((stderr, "<%s : %d> %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__);
(NSLog)((@"Hello"), );
fprintf(stderr, "-------\n");
} while (0);



#define NSLogRect(rect) NSLog(@"%s x:%.4f, y:%.4f, w:%.4f, h:%.4f", #rect, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)
#define NSLogSize(size) NSLog(@"%s w:%.4f, h:%.4f", #size, size.width, size.height)
#define NSLogPoint(point) NSLog(@"%s x:%.4f, y:%.4f", #point, point.x, point.y)

### 两个实际应用的例子


#define XCTAssertTrue(expression, format...) \
_XCTPrimitiveAssertTrue(expression, ## format)

#define _XCTPrimitiveAssertTrue(expression, format...) \
({ \
@try { \
BOOL _evaluatedExpression = !!(expression); \
if (!_evaluatedExpression) { \
_XCTRegisterFailure(_XCTFailureDescription(_XCTAssertion_True, 0, @#expression),format); \
} \
} \
@catch (id exception) { \
_XCTRegisterFailure(_XCTFailureDescription(_XCTAssertion_True, 1, @#expression, [exception reason]),format); \
}\
})


//调用 RACSignal是类的名字
RACSignal *signal = RACObserve(self, currentLocation);

//以下开始是宏定义
//rac_valuesForKeyPath:observer:是方法名
#define RACObserve(TARGET, KEYPATH) \
[(id)(TARGET) rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]

#define keypath(...) \
metamacro_if_eq(1, metamacro_argcount(__VA_ARGS__))(keypath1(__VA_ARGS__))(keypath2(__VA_ARGS__))

//这个宏在取得keypath的同时在编译期间判断keypath是否存在，避免误写
//您可以先不用介意这里面的巫术..
#define keypath1(PATH) \
(((void)(NO && ((void)PATH, NO)), strchr(# PATH, '.') + 1))

#define keypath2(OBJ, PATH) \
(((void)(NO && ((void)OBJ.PATH, NO)), # PATH))

//A和B是否相等，若相等则展开为后面的第一项，否则展开为后面的第二项
//eg. metamacro_if_eq(0, 0)(true)(false) => true
//    metamacro_if_eq(0, 1)(true)(false) => false
#define metamacro_if_eq(A, B) \
metamacro_concat(metamacro_if_eq, A)(B)

#define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE))

#define metamacro_if_eq0(VALUE) \
metamacro_concat(metamacro_if_eq0_, VALUE)

#define metamacro_if_eq0_1(...) metamacro_expand_

#define metamacro_expand_(...) __VA_ARGS__

#define metamacro_argcount(...) \
metamacro_at(20, __VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)

#define metamacro_at(N, ...) \
metamacro_concat(metamacro_at, N)(__VA_ARGS__)

#define metamacro_concat(A, B) \
metamacro_concat_(A, B)

#define metamacro_concat_(A, B) A ## B

#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) metamacro_head(__VA_ARGS__)

#define metamacro_dec(VAL) \
metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
//调用 RACSignal是类的名字 RACSignal *signal = RACObserve(self, currentLocation); 



OneV’s Den大大还有很多很棒的文章哟~~~

#define NSLog(format, ...)   fprintf(stderr, "<%s : %d> %s\n",                                           \

[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],  \

__LINE__, __func__);                                                        \

(NSLog)((format), ##__VA_ARGS__);                                           \

fprintf(stderr, "\n ------------------\n/ Hello David Day! \\\n\\ my Macro Log ~   /\n ------------------\n            \\\n             \\   ^__^\n                 (OO)\__________\n                 (__)\\          )\\/\\\n                     ||_______ _)\n                     ||       W |\n       YYy           ww        ww\n");

## #undef


#define NetworkOn //定义一个宏，如果该宏定义了，则在应用里使用网络

-(void)closeNetwork{//突然发生意外的情况，网络无法使用了，调用该方法，取消NetworkOn的宏定义
#undef NetworkOn
}



# 条件编译

## #if #else #endif

#if就和我们常用的条件语句的if使用方式一样，#if的后面跟上条件表达式，后面跟上一个#endif表示结束#if，虽说这玩意儿简单，但是用的好，对于某些取巧的工作特别容易实现。比如你现在有这样的需求，我的程序平时调试模式的时候需要打印一些log，但是发布模式的应用就不用再打印log了，怎么办？很多人就说发布的时候吧log语句一句一句的删除呗~ 那客户发烂咋说你写的东西是狗屎让你修改，所以你又要回来调试，当你调试的时候你菊花肯定一紧,以前的调试语句因为过于自信在发布的时候全都删除了，又想不到发布后又被要求修改~，有基友就说了，那就不删除log语句呗，反正是打印到控制台的信息，用户又看不到~，果然没有安全意识，企业开发不是学雷锋，不用把你的所有log都写在日记本，有时候你的软件被破解的原因就是因为你的调试信息出卖了你。安全意识不可无，不然老王替你生孩子~~~~~。


//swift语言
#if DEBUG
func dlog<T>(object: T) {
println(object)
}
#else
func dlog<T>(object: T) {}
#endif



DEBUG是xcode的预定义的宏，这个东西多的很呢，要慢慢挖掘呢。 以后打印log你都只使用dlog()这个函数，如果你是在调试模式的时候就会打印，否则就不会打印了。


#if !__has_feature(objc_arc)
//如果没有开启ARC这里可以做一些错误处理 比如：
#error "啊 啊 啊~ 伦家需要ARC"
#endif


#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0
//如果iOS版本低于7.0，这里可以干一些事情
#endif

#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#else
//这货是IPhone
#endif

## #if define  #ifdef  #ifndef  #elif

#if define = #ifdef

#if !define = #ifndef

#elif = "else if"

# 错误、警告处理

## #error


#if !__has_feature(objc_arc)
#error "我的低调不是你装逼的资本！这个库需要开启ARC，不然你别用！"
#endif

## 谈谈Objective-C的警告

### 在Xcode中开启额外警告提示

Xcode的工程模板已经为我们设置开启了一些默认和常用的警告提示，这些默认设置为了兼容一些上年头的项目，并没有打开很多，仅是指对最危险和最常见的部分进行了警告。这对于一个新项目来说这是不够用的（至少对我来说是不够用的），在无数前辈大牛的教导下，首先要做的事情就是打开尽可能多的警告提示。

• -Wall 并不是所有警告。这一个警告组开启的是编译器开发者对于“你所写的代码中有问题”这一命题有着很高的自信的那些警告。要是在这一组设定下你的代码出现了警告，那基本上就是你的代码真的存在严重问题了。但是同时，并不是说打开Wall就万事大吉了，因为Wall所针对的仅仅只是经典代码库中的为数不多的问题，因此有一些致命的警告并不能被其捕捉到。但是不论如何，因为Wall的警告提供的都是可信度和优先级很高的警告，所以为所有项目（至少是所有新项目）打开这组警告，应该成为一种良好的习惯。
• -Wextra 如其所名，-Wextra组提供“额外的”警告。这个组和-Wall组几乎一样有用，但是有些情况下对于代码相对过于严苛。一个很常见的例子是，-Wextra中包含了-Wsign-compare，这个警告标识会开启比较时候对signed和unsigned的类型检查，当比较符两边一边是signed一边是unsigned时，产生警告。其实很多代码并没有特别在意这样的比较，而且绝大多数时候，比较signed和unsigned也是没有太大问题的（当然不排除会有致命错误出现的情况）。需要注意，-Wextra-Wall是相互独立的两个警告组，虽然里面打开的警告标识有个别是重复的，但是两组并没有包含的关系。想要同时使用的话必须在Other C Flags中都加上
• -Weverything 这个是真正的所有警告。但是一般开发者不会选择使用这个标识，因为它包含了那些还正在开发中的可能尚存bug的警告提示。这个标识一般是编译器开发者用来调试时使用的，如果你想在自己的项目里开启的话，警告一定会爆棚导致你想开始撞墙..

### 控制警告，局部加入或关闭

Clang提供了我们自己加入警告或者暂时关闭警告的办法。

//Generate a warning
#pragma message "Warning 1"

//Another way to generate a warning
#warning "Warning 2"

//Generate an error to fail the build.
#error "Something wrong"

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"

int a;

#pragma clang diagnostic pop

# 编译器控制

## #pragma

### #pragma mark

#pragma mark -
#pragma mark 这里是applicationWillTerminate方法呀~
- (void)applicationWillTerminate:(UIApplication *)application {
}

### #pragma clang diagnostic pop

#pragma非常复杂需要你对编译器底层非常的了解，只有当你开发一些比较底层的framework的时候才可能比较多用的，我是初学者，我不用我怕谁？

# 其他

## #line

C语言中的__LINE__用以指示本行语句在源文件中的位置信息。而#line就是可以改变当前行的行号在编译器中的表示，并且之后的行号也会相应的改变，比如

1 #include <stdio.h>
2 main(){
3     printf("%d\n",__LINE__);
4 #line 100  //指定下一行的__LINE__为100
5     printf("%d\n",__LINE__);
6     printf("%d\n",__LINE__);
7     };



3
100
101

# 结语

这篇文章完了~ 这篇文章既是我学习的笔记也是我思考的感悟和一些技术资料的集合，我很用心的写，白天上班写代码，晚上要准备本科的毕业设计，周末陪女朋友，所以我只有在拉屎蹲坑的时候一点一点写出来的，其中一定错漏百出，所以希望看到文章的朋友尽情的喷！砖头不要省！反正我都写代码了我还怕谁？

但是最终嘛，我还是希望能帮到刚刚开始学习的朋友们，毕竟你丫的写的代码太差，也是在污染环境呀！！不是开玩笑！不单单污染环境，你还破坏世界和平，如果你的代码效率很差，你想想如果你的代码运行在电脑上或者手机上那么是不是很费电？费电了是不是要烧很多煤炭来发电？大气中的有害气体是不是越来越多了？温室效应，臭氧层破坏，土地沙漠化，北京沙尘暴，拿钱治理，钱，贪污，腐败，革命，美国参战，朝鲜怒点核武……都怪你！！知道了吧。

还有哦，转载不注明！BUG一生随。你自己看着办

写代码就是在维护世界和平，谢谢 @戴伟来

posted @ 2015-01-20 14:45  DavidDay  阅读(9599)  评论(15编辑  收藏