何时在Objective-C中使用宏

Aru*_*run 3 macros objective-c ios

根据定义"宏是一个已经给出名称的代码片段.每当使用该名称时,它将被宏的内容替换".我曾经在我的班级中多次使用的代码中使用宏,基本上是硬编码的字符串.

我的怀疑是:

  1. 何时使用宏
  2. 声明宏时的好坏做法

为了解释我的第二个疑问,我在我的UIView中有一个名为"menuBurger.png"的图像文件.

[self.hamBurgerButton setImage:[UIImage imageNamed:@"menuBurger.png"] forState:UIControlStateNormal];
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,有两种方法可以创建宏

情况1 : #define HAMBURGER_BUTTON_IMAGE_NAME @"menuBurger"

案例2: #define HAMBURGER_BUTTON_IMAGE [UIImage imageNamed:@"menuBurger"]

在案例2中我声明宏的方式有什么不对吗?使用宏而不是对象是一个好习惯(如果是2,它返回一个UIImage对象)?

vit*_*rmm 8

1)何时使用宏

让我先介绍另一个StackOverflow答案:

宏是预处理器定义.这意味着在编译代码之前,预处理器会扫描您的代码,并且除了其他方面之外,还会在您看到宏名称的任何地方替换宏的定义.它没有比这更聪明的事情.

参考:https://stackoverflow.com/a/20837836/4370893

基于此,在某些情况下,使用宏将使您的代码不仅更易读,而且不太适合错误.我将列出其中一些:

1.避免字符串重复

第一种情况是你的程序必须处理不同类中的许多类似字符串,例如当你处理只存在于程序中的字典时.

#define USERNAME_KEY @"username"
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,您有一个带@"username"字符串的宏,您可以使用它而不是一直写入@"username".它的一个好处是你永远不必处理拼写错误.错误地写出关键名称将成为过去的事情.

有些人喜欢使用static const's,但是如果它更好或者更好,则取决于你的需求.如果您static const.h文件添加一个文件,它将可供任何导入它的类使用,并且它只会分配一次.

但是,如果您需要static const在应用程序的多个部分中使用宏,或者只需将它们添加到项目.pch文件中.由于宏在编译时被替换,因此每次使用它们时都会分配它们,但是static const将为每个类分配,即使是在不使用它的情况下也是如此.就像我之前说的那样,这取决于你的需求.

2.多个编译选项

Marcos在编译时被替换,这意味着您可以使用它们在单个项目中创建应用程序的多个版本.在一个示例中,假设您的应用程序具有常规版本(macOS 10.9+兼容)和旧版本(macOS 10.6+).维护两个项目会很糟糕,所以你可以使用宏来解决这个问题.

#define IS_LEGACY_VERSION __MAC_OS_X_VERSION_MAIN_REQUIRED < __MAC_10_9
Run Code Online (Sandbox Code Playgroud)

上面的行创建了一个IS_LEGACY_VERSION宏,它BOOL告诉您项目是否需要低于macOS 10.9的版本.这允许您在编译结果更改的其他情况下使用宏:

#if IS_LEGACY_VERSION == TRUE
    // Only in legacy app
#else
    // Only in regular app
#endif
Run Code Online (Sandbox Code Playgroud)

看到上面不同的if/else?这可以在任何地方使用,甚至可以在外部函数中使用,以在宏的条件下使任何事情发生(或甚至存在).

当你想要使用过去不支持的东西时,这是特别有用的,所以你需要添加一个全新的类来支持它,比如阅读JSON.您可以将该函数添加到NSData:

-(id)jsonObject
{
#if IS_LEGACY_VERSION == FALSE
    return [NSJSONSerialization JSONObjectWithData:self options:0 error:nil];
#else
    NSString* string = [[NSString alloc] iniWithData:self encoding:NSUTF8StringEncoding];
    return [string jsonObject];
#endif
}
Run Code Online (Sandbox Code Playgroud)

[NSString jsonObject]函数来自SZJsonParser.您可以将这两个文件添加#if IS_LEGACY_VERSION == TRUE到项目中,添加到两个文件的开头和#endif结尾.然后你只需导入"SZJsonParser.h"并完成!该[NSData jsonObject]函数适用于常规版本和旧版本,并且常规版本中没有SZJsonParser的痕迹,并且旧版本中没有NSJSONSerialization的痕迹.

问:你不能直接使用SZJsonParser吗?

当然,但也许有一天我将不得不放弃应用程序的Legacy版本,这部分应用程序将不得不死掉.此外,Apple的NSJSONSerialization比SZJsonParser更加优化,所以如果我能为普通版用户提供更好的体验,为什么不呢?

3.轻松更换字符串

想象一下,来自示例1的字符串是来自JSON请求的密钥,该请求被转换为字典.如果某人决定该密钥将不再存在"username",而是"name"替换它将非常容易.

这也适用于URL,文件路径,主机,甚至更复杂的对象,如颜色,但您应该知道何时使用它.有了它,您可以创建一个define包含所有应用程序URL 的列表,这样它们就在一个地方,使它们更容易找到.static const也有这样的优势.

4.结合上面的那些

如果结合上述三个例子给出的案例,可能性很多.宏比看起来更有用.

2)声明宏时的好的和坏的做法

我将使用你自己的案例有一个好的和坏的做法的例子:

#define HAMBURGER_BUTTON_IMAGE_NAME     @"menuBurger"
Run Code Online (Sandbox Code Playgroud)

好的做法:有了这个,您可以从应用程序的任何位置按名称调用汉堡按钮图像,如果名称发生变化,替换将非常容易.另外,这给你的变量一个名字,这比[UIImage imageNamed:@"menuBurger"]直接调用要好得多(再次,不要忘记static const解释).

#define HAMBURGER_BUTTON_IMAGE          [UIImage imageNamed:@"menuBurger"]
Run Code Online (Sandbox Code Playgroud)

糟糕的做法:这会占用你应用中的部分逻辑并将其隐藏在定义中,所以这不是一件好事.在逻辑方面,你必须注意它们.我将举几个例子:

#define RGB(r, g, b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0]
Run Code Online (Sandbox Code Playgroud)

好的做法:你正在简化一个函数,它没有隐含的逻辑.

#define ScreenWidth [[UIScreen mainScreen] bounds].size.width
Run Code Online (Sandbox Code Playgroud)

好的做法:你减少了对a的大函数调用define,这可能非常有用.但是,你应该小心; 你只能将它添加到导入了UIKit的类中,所以这可能是一种危险的方法.

#define DATE_COMPONENTS NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
Run Code Online (Sandbox Code Playgroud)

好的做法:因为它是用约束构建的值,所以它将具有固定值.

#define NavBar self.navigationController.navigationBar
Run Code Online (Sandbox Code Playgroud)

不好的做法:使用self可能会导致你犯错误,因为你将被限制在某种类别.请记住,宏在编译时被替换,因此self根据您使用它的位置将是一个不同的对象.

#define ApplicationDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])
Run Code Online (Sandbox Code Playgroud)

不好的做法:如果你的类没有导入会失败的AppDelegate,这会导致你犯错.

#define MAX(x, y) ((x) > (y) ? (x) : (y))
Run Code Online (Sandbox Code Playgroud)

非常糟糕的做法: x和y都使用了两次,这可能会导致问题.你可以在这里找到一个解释:http: //weblog.highorderbit.com/post/11656225202/appropriate-use-of-c-macros-for-objective-c

宏的其他使用示例(不一定都是好的做法):