原文网址:http://tutuge.me/2015/03/11/Effective-Objective-C-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0-Item-4-%E5%A6%82%E4%BD%95%E6%AD%A3%E7%A1%AE%E5%AE%9A%E4%B9%89%E5%B8%B8%E9%87%8F/

前言

写博客果然比光看书要花时间=。=,书都快看完了,才写到第4节。但是总结一遍,的确印象深刻啊~~

这次的主题是“常量”,非常常用,又非常重要的东西~良好的代码规范、设计,少不了各种常量

Item 4 - Prefer Typed Constants to Preprocessor #define

本节着重对比了常量的定义形式,类型常量和#define的区别、各自的特点。最后得出,我们应该用带有类型的常量,而不是#define。

一个简单的示例

应用中,少不了各种动画,也就少不了设定动画的时间长度,一般来说,我们会设定短、中、长几种时间常量,用于不同的场合,了解C语言的童鞋估计对“#define”宏定义不陌生,于是,可能就会如下这么定义:

1
2
3
#define ANIMATION_DURATION_SHORT 0.3
#define ANIMATION_DURATION_MIDDLE 0.6
#define ANIMATION_DURATION_LONG 1.0

于是,所有用到动画时长的地方,直接用这几个宏定义就行了。

乍一看,似乎没什么问题。

类型+不可变

先来看看宏定义干了什么。
总的来说,#define就是“替换”,在编译时,将一切宏定义替换成定义后面的内容。(参考百度百科

关键在于:

  • 宏定义不会检查替换的“类型”,只要遇到,就做替换。
  • 宏定义不保证“不可变”,因为可以重复定义,不能保证值不变。(这个我觉得是最容易让人忽略的地方)

所以,用宏定义定义常量,很“危险”。

正确的做法

恰当的常量,应该具备合适的常量名字、正确的类型,还有const、extern等关键字的修饰,当然,还要根据常量适用的“范围”,做出恰当的处理。一下举例说明。

只在函数中用的常量

只在函数中用的常量:

1
2
3
4
5
- (void)runAnimation {
//动画时间长度常量
static const NSTimeInterval kAnimationDurationLong = 1.0f;
//...
}

static、const定义了它是静态不可变的;NSTimeInterval则“精确”指定了常量的类型。

只在一个“.m”文件中使用的常量

在类的实现文件“xxx.m”文件中定义常量,也是很常见的。
你可能会觉得,既然是一个类使用的,那就放在类的头文件里面定义不就好了。
但是这么想是错的=。=
因为所有要用到这个类的文件,都会无形当中包含了这些常量声明,将不必要的数据暴露在外面,这样是违反设计原则的,并且,如果常量名字取得不恰当,还有可能造成冲突。

所以,应该如下:

1
2
3
4
5
6
7
8
//XXX.m

//必须要static
static const NSTimeInterval kAnimationDurationLong = 1.0f; @implementation XXX
//...
@end

需要注意的点:

  • 一定要放在.m文件中。
  • 必须是static,表示此常量作用域只在此.m文件中。如果不加static的话,常量就会在全局作用域中声明,可能会导致跟其他的常量冲突。
  • const,当然。
  • NSTimeInterval,确定的类型。
  • kAnimationDurationLong,“k”开头的命名,也算是Apple的规范了吧,内部常量统一以“k”开头。

全局常量

一般来说,最常见的全局常量就是发广播Notification时用的Notification的名字,往往都是一些字符串,下面就以这个为例子:

假设我们的类叫“TTGClass”,我们的类会向外发送Notification,所以需要定义一个Notification的名字常量供外界注册,如下:

1
2
3
4
5
//TTGClass.h
extern NSString * const TTGClassWorkBeginNotification; //TTGClass.m
NSString * const TTGClassWorkBeginNotification = @"TTGClassWorkBeginNotification";

关键:

  • 头文件中只是做声明,不做定义。所以用extern表示常量在别处定义的,尽量隐藏细节。
  • 类名做常量名字的开头,这个非常关键,因为Objective-C里面没有像Java那样的“包”机制,所以必须靠命名来划分不同的类,常量当然也要遵循这个规则。
  • NSString,确定的类型;const,表明常量;Notification后缀,表明用途。这些都是需要注意的。

总结

良好的代码,总是少不了定义各种常量,以避免“魔鬼数字、魔鬼字符串”。所以我们应该尽量避免少用#define定义常量,而是用带有类型的、const的常量,并且尽可能的缩小常量的作用域。

暴露的细节越少,出错的机会也就越小(忘了从哪里看到的=。=)

【转】Effective-Objective-C-读书笔记-Item-4-如何正确定义常量 -- 不错的更多相关文章

  1. [.NET] 《Effective C#》读书笔记(二)- .NET 资源托管

    <Effective C#>读书笔记(二)- .NET 资源托管 简介 续 <Effective C#>读书笔记(一)- C# 语言习惯. .NET 中,GC 会帮助我们管理内 ...

  2. 《More Effective C#》读书笔记

    <More Effective C#>这本书,大概是四年前看完的,但只整理了一部分读书笔记,后面有时间的话,会陆续补充的. More Effective C# :使用泛型 More Eff ...

  3. 《More Effective C++》读书笔记(零)Basic 基础条款

    这是篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点.我推荐学C++的人都好好读一遍Effective C++ 系列,真是 ...

  4. 《More Effective C++ 》读书笔记(二)Exception 异常

    这事篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点.我推荐学C++的人都好好读一遍Effective C++ 系列,真是 ...

  5. Effective Objective-C 的读书笔记

    本文主要是摘录了 <Effective Objective-C 2.0>一书中提到的编写高质量iOS 代码的几个方法. 1 熟悉Objective -C 1.1 OC 起源 OC 为C语言 ...

  6. 《Effective C++》读书笔记 条款02 尽量以const,enum,inline替换#define

    Effective C++在此条款中总结出两个结论 1.对于单纯常量,最好以const对象或enum替换#define 2.对于形似函数的宏,最好改用inline函数替换#define 接下来我们进行 ...

  7. 《Effective Java》 读书笔记(六)避免创建不必要的对象

    java 有很多修饰类的属性的关键字:常用的static,final 说说final和static吧,平时在编程的时候,这两个关键字很多时候都觉得可有可无,最多的时候就是他们俩同时出现----定义常量 ...

  8. 《Effective Java》 读书笔记(二) 在构造参数过多的时候优先考虑使用构造器

    刚开始看见这个标题的时候,我想到了python可以选择初始化参数的语法,C++.C#能有默认参数. 为什么Java什么都没有~~ 好吧,我们是使用构造器来实现它. 1.当一个类的构造函数需要很多构造函 ...

  9. 《Effective Java》读书笔记(一)之创建和销毁对象

    最近在研读<Effective Java>一书,读书不做点笔记,感觉很容易就忘掉,于是用本篇博客来记录阅读此书的笔记. 郑重声明: 由于是<Effective Java>一书的 ...

随机推荐

  1. Fedora 17安装NFS

    1.NFS概述 NFS(Network File System)是一种分布式文件系统,允许网络中的安装不同操作系统的计算机间共享文件和外设,所以它的通讯协定设计与主机及作业系统无关. 它是由SUN公司 ...

  2. (转)sqlserver游标概念与实例全面解说

    首先声明:该文章转自http://www.cnblogs.com/wudiwushen/archive/2010/03/30/1700925.html  的博客 引言  我们先不讲游标的什么概念,步骤 ...

  3. owa Your request can't be completed right now. Please try again later.

    Your request can't be completed right now. Please try again later.

  4. Indri查询命令及Java调用并保存结果

    查询参数 index Indri索引库路径.在参数文件中像/path/to/repository这样指定,在命令行中像-index=/path/to/repository这样指定.该参数可以设置多次来 ...

  5. 使用Schtasks命令的注意事项

    在使用Schtasks命令时遇到了两个棘手的问题,耗费了一点时间,出现这个问题的时候查找网络资源也找不到真正的解决方案,最后还是自己悟出来了原因,所以在此把这些问题记录下来.如下: 服务器环境:win ...

  6. 1020: [SHOI2008]安全的航线flight - BZOJ

    Description在设计航线的时候,安全是一个很重要的问题.首先,最重要的是应采取一切措施确保飞行不会发生任何事故,但同时也需要做好最坏的打算,一旦事故发生,就要确保乘客有尽量高的生还几率.当飞机 ...

  7. VC中不同类型DLL及区别

    1. DLL的概念可以向程序提供一些函数.变量或类. 静态链接库与动态链接库的区别:(1)静态链接库与动态链接库都是共享代码的方式.静态链接库把最后的指令都包含在最终生成的EXE文件中了:动态链接库不 ...

  8. 1027-Quicksum

    描述 A checksum is an algorithm that scans a packet of data and returns a single number. The idea is t ...

  9. Head First 设计模式笔记:单例模式

    单例模式 确保一个类只有一个实例,并提供一个全局访问点. 类图: Singleton static uniqueInstance //其他属性... static getInstance() //其他 ...

  10. [itint5]支持删除的后继查询

    http://www.itint5.com/oj/#49 这一题一开始想到是用HashSet+链表来做,链表记录prev和next.这样也可以,后来看到都是连续的整数,而且交流了一下觉得可以用类似并查 ...