Ios 在Objective-C中何时使用宏

Ios 在Objective-C中何时使用宏,ios,objective-c,macros,Ios,Objective C,Macros,根据定义,“宏是给定名称的代码片段。每当使用名称时,它都会被宏的内容替换”。我曾经使用宏来处理那些在我的课堂上多次使用的代码,基本上是硬编码字符串 我的疑问是: 何时使用宏 声明宏时的好做法和坏做法 为了解释我的第二个疑问,我在UIView中有一个名为“menuBurger.png”的图像文件 [self.hamBurgerButton setImage:[UIImage imageNamed:@"menuBurger.png"] forState:UIControlStateNormal];

根据定义,“宏是给定名称的代码片段。每当使用名称时,它都会被宏的内容替换”。我曾经使用宏来处理那些在我的课堂上多次使用的代码,基本上是硬编码字符串

我的疑问是:

  • 何时使用宏
  • 声明宏时的好做法和坏做法
  • 为了解释我的第二个疑问,我在UIView中有一个名为“menuBurger.png”的图像文件

    [self.hamBurgerButton setImage:[UIImage imageNamed:@"menuBurger.png"] forState:UIControlStateNormal];
    
    在这种情况下,有两种方法可以创建宏

    案例1:
    #定义汉堡包按钮(图像)名称@“menuBurger”

    案例2:
    #定义汉堡按钮图像[UIImage ImageName:@“menuBurger”]

    在案例2中,我声明宏的方式是否有任何错误?使用宏而不是对象(在案例2中它返回UIImage对象)是否是一种好的做法?

    1)何时使用宏

    让我先参考另一个答案:

    宏是预处理器定义。这意味着以前 你的代码被编译,预处理器扫描你的代码,然后 其他的东西,替换宏的定义,不管它在哪里 查看宏的名称。没有比这更聪明的了 那个

    参考:

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

    1。避免字符串重复

    第一种情况是,当您的程序必须处理不同类中的大量相似字符串时,就像处理仅存在于程序中的词典时一样

    #define USERNAME_KEY @"username"
    
    在上面的示例中,您有一个带有
    @“username”
    字符串的宏,您可以使用它来代替一直编写
    @“username”
    。它的好处之一是,你永远不必处理打字错误。将密钥名称写错将是过去的事情

    有些人更喜欢使用static const,但是如果它更好或者不更好,这取决于你的需要。如果将
    静态常量
    添加到
    .h
    文件中,则导入该文件的任何类都可以使用该文件,并且只分配一次

    但是,如果您需要在应用程序的多个部分中使用宏或静态常量,您只需将它们添加到项目
    .pch
    文件中即可。由于宏是在编译时被替换的,所以每次使用宏时都会分配宏,但是
    静态常量
    将分配给您拥有的每个类,即使在您不使用它的类中也是如此。就像我之前说的,这取决于你的需要

    2。多个编译选项

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

    #define IS_LEGACY_VERSION __MAC_OS_X_VERSION_MAIN_REQUIRED < __MAC_10_9
    
    看到上面不同的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]
    函数的来源。您可以将两个文件都添加到项目中,将
    #if IS_LEGACY_VERSION==TRUE
    添加到两个文件的开头,并将
    #endif
    添加到它们的结尾。然后导入“SZJsonParser.h”并完成!
    [NSData jsonObject]
    函数在常规版本和旧版本中都可以工作,并且在常规版本中没有SZJsonParser的痕迹,在旧版本中也没有NSJSONSerialization的痕迹

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

    当然可以,但也许有一天我不得不放弃应用程序的旧版本,而应用程序的这一部分将不得不消亡。另外,苹果的NSJSONSerialization比SZJsonParser优化得多,所以如果我能给普通版本的用户更好的体验,为什么不呢

    3。易于更换字符串

    假设示例1中的字符串是JSON请求中的一个键,该请求被转换为字典。如果有人决定密钥不再是
    “username”
    ,而是
    “name”
    ,那么您很容易替换它

    这也适用于URL、文件路径、主机,甚至更复杂的对象,如颜色,但您应该知道何时使用它或不使用它。这样,您就可以创建一个包含所有应用程序URL的
    定义
    列表,使它们都位于一个位置,从而更容易找到<代码>静态常量
    也有同样的优势

    4。将以上各项组合起来

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

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

    我将用你自己的案例来举例说明好的和坏的做法:

    #define HAMBURGER_BUTTON_IMAGE_NAME     @"menuBurger"
    
    良好实践:这样,你就可以在应用程序中的任何位置按名称调用汉堡按钮图像,如果它的名称发生更改,则替换将非常简单。这也为变量提供了一个名称,这比直接调用
    [UIImage imageNamed:@“menuBurger”]
    要好得多(同样,不要忘记
    静态常量的解释)

    糟糕的做法:将应用程序中的部分逻辑隐藏在define中,因此这不是一件好事。当涉及到逻辑时,你必须注意它们。
    #define HAMBURGER_BUTTON_IMAGE_NAME     @"menuBurger"
    
    #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 DATE_COMPONENTS NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
    
    #define NavBar self.navigationController.navigationBar
    
    #define ApplicationDelegate ((AppDelegate *)[[UIApplication sharedApplication] delegate])
    
    #define MAX(x, y) ((x) > (y) ? (x) : (y))