何时在Objective-C中使用宏

阿伦

根据定义,“宏是已被赋予名称的代码片段。每当使用该名称时,它就会被宏的内容替换”我曾经在类中多次使用那些宏的代码,这些代码基本上是硬编码的字符串。

我的怀疑是:

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

为了解释我的第二个疑问,我的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)何时使用宏

首先让我参考另一个StackOverflow答案:

宏是预处理器定义。这意味着在编译代码之前,预处理程序会扫描您的代码,并在发现宏名称的任何地方替换宏的定义。它没有比这更聪明的了。

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

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

1.避免字符串重复

第一种情况是您的程序必须处理不同类中的许多相似字符串,例如处理仅存在于程序中的字典时。

#define USERNAME_KEY @"username"

在上面的示例中,您具有一个带有@"username"字符串的宏,您可以使用它代替一直写@"username"它的好处之一是您将永远不必打错字。错误输入密钥名称已成为过去。

有些人更喜欢使用static const,但是否更好,则取决于您的需求。如果将a添加static const.h文件中,则任何导入该文件的类都可以使用它,并且仅分配一次。

但是,如果您需要static const在应用的多个部分中使用Macros或,则只需将它们添加到项目.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_VERSION宏,BOOL告诉您项目是否需要低于macOS 10.9的版本。这使您可以在编译结果发生变化的不同情况下使用宏:

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

看到上面的其他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
}

[NSString jsonObject]函数来自SZJsonParser您可以将两个文件都添加到项目中,也可以将其添加#if IS_LEGACY_VERSION == TRUE到两个文件的开头和#endif结尾。然后,您只需导入“ SZJsonParser.h”即可完成![NSData jsonObject]函数在常规版本和旧版本中均可使用,在常规版本中没有SZJsonParser的痕迹,在旧版本中也没有NSJSONSerialization的痕迹。

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

当然可以,但是也许有一天我将不得不放弃该应用程序的旧版本,并且该应用程序的这一部分将不得不消亡。另外,Apple的NSJSONSerialization比SZJsonParser更优化,因此,如果我可以为普通版用户提供更好的体验,为什么不呢?

3.轻松更换字符串

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

这也适用于URL,文件路径,主机以及甚至更复杂的对象(如颜色),但是您应该知道何时使用它。这样一来,您可以创建define带有所有应用程序URL的列表,以便将它们都放在一个位置,从而更易于查找。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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章