何时在Objective-C中使用宏

时间:2017-03-15 10:42:20

标签: ios objective-c macros

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

我的怀疑是:

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

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

    [self.hamBurgerButton setImage:[UIImage imageNamed:@"menuBurger.png"] forState:UIControlStateNormal];
    

    因此,在这种情况下我可以通过两种方式创建宏

    案例1: #define HAMBURGER_BUTTON_IMAGE_NAME @"menuBurger"

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

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

1 个答案:

答案 0 :(得分:8)

1)何时使用宏

让我先引用另一个StackOverflow答案:

  

宏是预处理器定义。这意味着以前   你的代码被编译,预处理器扫描你的代码,然后   其他的东西,无论在哪里,都可以替代宏的定义   看到你的宏的名字。它没有做任何比聪明更聪明的事情   这一点。

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

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

<强> 1。避免字符串重复

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

#define USERNAME_KEY @"username"

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

有些人更喜欢使用static const,但如果它更好或没有,则取决于您的需求。如果您将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

上面的行创建了一个IS_LEGACY_VERSIONBOOL,告诉您项目是否需要低于macOS 10.9的版本。这允许您在编译结果发生变化的不同情况下使用宏:

#if IS_LEGACY_VERSION == TRUE
    // Only in legacy app
#else
    // Only in regular app
#endif

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

当你想要使用过去不支持的东西时,这是非常有用的,所以你需要添加一个全新的类来支持它,比如阅读JSON&#39; s。您可以将该功能添加到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
}

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

  

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

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

第3。易于更换字符串

想象一下,来自示例1的字符串是来自JSON请求的密钥,该请求被转换为字典。如果有人决定该密钥不再是"username",而是"name",那么您将很容易替换它。

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

<强> 4。结合以上

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

2)声明宏

时的好坏做法

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

#define HAMBURGER_BUTTON_IMAGE_NAME     @"menuBurger"

良好做法:您可以通过应用程序中任何位置的名称来调用汉堡按钮图像,如果更改名称,替换将非常简单。另外,这会为您的变量命名,这比直接调用[UIImage imageNamed:@"menuBurger"]要好得多(再次,不要忘记static const解释)。

#define HAMBURGER_BUTTON_IMAGE          [UIImage imageNamed:@"menuBurger"]

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

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

良好做法:您正在简化一项功能,其中没有隐含的逻辑。

#define ScreenWidth [[UIScreen mainScreen] bounds].size.width

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

#define DATE_COMPONENTS NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit

良好做法:由于它是使用约束构建的值,因此它将具有固定值。

#define NavBar self.navigationController.navigationBar

糟糕的做法:使用self可能会导致您犯错误,因为您将被限制在某种类别。请记住,宏在编译时被替换,因此self将是一个不同的对象,具体取决于您使用它的位置。

#define ApplicationDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])

糟糕的做法:如果您的班级没有导入失败的AppDelegate,这可能会导致错误。

#define MAX(x, y) ((x) > (y) ? (x) : (y))

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

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