根据定义,“宏是已被赋予名称的代码片段。每当使用该名称时,它就会被宏的内容替换”。我曾经在类中多次使用那些宏的代码,这些代码基本上是硬编码的字符串。
我的怀疑是:
为了解释我的第二个疑问,我的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] 删除。
我来说两句