NSNotification Name 最佳写法
本文主要借探讨NSNotificationName的最佳写法的机会,学习下extern, static, const, #define 和常量指针与指针常量等的特性和用法。
1.NSNotification标准使用方法
发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:QLPosterDidPostNotification object:nil];
接收通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceive:) name:QLPosterDidPostNotification object:nil];
还要注意在dealloc中移除通知哈
2.通知的发送者和接收者都需要知道NSNotification name,如何保证双方统一
在iOS中,通知是为了方便解耦,因此通知的发送者和接收者往往不在同一个类/文件中
但是无论是发送者还是接收者,他们使用的通知名字却需要一致,如上例的QLPosterDidPostNotification在两处地方都使用到了
那么如何保证2处地方使用的通知名字是同一个呢?
最蠢的做法就是在各处需要用到这个通知的地方自己定义一个QLPosterDidPostNotification
这种做法违背了DRY原则,简直忍无可忍,一旦违背了DRY原则,代码的可读性将会变得非常差,维护起来会非常恶心!
最佳实践是一处地方定义,多处地方使用
3.最佳写法
QLPoster.h
extern NSString *const QLPosterDidPostNotification;
QLPoster.m
NSString *const QLPosterDidPostNotification = @"QLPosterDidPostNotification";
QLReceiver.h
extern NSString *const QLPosterDidPostNotification;
4.怎么用
首先,很自然的,我们先在QLPoster.m中声明定义一个通知的名字
NSString *const QLPosterDidPostNotification = @"QLPosterDidPostNotification";
其次,为了让外面的人统一使用该变量,我们需要在QLPoster.h中将该变量暴露出去,并且加上extern,但不需要赋值(因为是声明)。目的就是为了告诉外部调用者,我有QLPosterDidPostNotification这个变量,它是什么内容你们别管,直接用就行了
然后QLReceiver要来调用啦,直接把QLPoster.h中关于变量声明的这句代码直接copy到自己的.h就行啦(因为这也是声明)
5.为什么不用#define
static const 是十分常见的组合,这里可以先把问题转为 static const 和 #define 的区别。
static const和#define的异同是:
相同点:编译器根本不会创建符号,预编译时把所有遇到的变量都替换为常值
不同点:但是static const定义的常量带有类型信息(可以指明常量是int, double, ...),便于理解
由于#define定义的常量不含类型信息,编译器只是会在编译前据此执行查找与替换操作。即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量不一致
6.extern是什么(为什么不用static const)
extern int a;//声明一个全局变量a
int a; //定义一个全局变量a
extern int a = ;//定义一个全局变量a并给初值
int a = ;//定义一个全局变量a并给初值
定义只能有1处,但声明可以有多处
定义引起内存分配,声明则不会
A.m
NSString *hello = @"hello";
B.m中不需要#import "A.m",直接
extern NString *hello;
NSLog(@"%@", hello); //输出 hello
非常厉害,不需要引用相关头文件就能使用其值!
变量的声明默认就是extern
变量的声明默认就是extern
变量的声明默认就是extern
重要的事情说3次了
假如A.m不想被B用extern找到,怎么办?只需要加个static
A.m
static NSString *hello = @"hello";
static表示该值只会在本文件(.m)中使用哈,别人看不到的
假如声明此变量时不加static,则编译器会为它创建一个“外部符号”(external symbol)
假如C.m也和A.m一样,都有一个NSString *hello = @"hello";
那就会编译失败,因为有2个外部变量hello
7.为什么加const
通知名称一般是固定不可变的,且不希望外部修改其值,所以加上const无非是最正确的选择
8.为什么是NSString *const 而不是 NSString const *
这就是C/C++中说到的常量指针和指针常量的区别了
const写在*前面,则该指针可被重新赋值,而指针指向的内容不可被重新赋值
const写在*后面,则该指针指向的内容可被重新赋值,而指针本身不可被重新赋值(即不能指向其他内存)
回到iOS中来,我们修改NSString的值,是怎么修改
NSString *str = @"";
str = @"";
注意哦,str = @"456";相当于(不代表就一定是)str = [[NSString alloc] initWithString:"456"];
就是说,iOS中,对NSString的修改一般都是让其指向一块新的内存
所以为了防止外部改变通知名字的值,我们一般将const写在*后面
9.规范的NSNotification Name命名方式
[Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification
(1)QLPosterDidPostNotification 而不是 kDidPostNotification
以k开头的一般是类内自己使用的static const变量,如果需要提供给外部使用,最好将自己的类名作为前缀
通知一般都不是只给自己用的,所以需要将自己的类名作为前缀
声明为extern的常量要出现在全局符号表中,所以其名称应加以区隔,通常用与之相关的类名做前缀。
(2)Did/Will表示动作的已经结束或即将开始,以明确通知抛出的时机
(3)QLPosterDidPostNotification 而不是 QLPosterDidPostNoti
通知名称这里宁愿名字长也不要引起歧义(苹果的命名一向被吐槽太长了)
NSNotification Name 最佳写法的更多相关文章
- Android启动活动的最佳写法
1.我们一般启动另一个活动的方式是: Intent intent = new Intent(MainActivity.this,SecondActivity.class); intent.putExt ...
- JavaScript 定义类的最佳写法——完整支持面向对象(封装、继承、多态),兼容所有浏览器,支持用JSDuck生成文档
作者: zyl910 [TOC] 一.缘由 由于在ES6之前,JavaScript中没有定义类(class)语法.导致大家用各种五花八门的办法来定义类,代码风格不统一.而且对于模拟面向对象的三大支柱& ...
- Java单实例的最佳写法
前言:代码简洁与性能高效无法两全其美,本文章专注于大并发程序的性能,如果您追求代码简洁,本文章可能不太适合,因为本文章主要讨论如何写出在高并发下也能运行很好的代码. 并文章属于Java并发编程实战中例 ...
- Android学习之启动活动的最佳写法
•开始热身 通过之前的学习,我们现在可以很容易的启动一个活动: 首先通过 Intent 构造出当前的 "意图",然后调用 startActivity() 方法将活动启动起来: ...
- Android开发之启动Activity的最佳写法
从MainActivity跳转到SecondActivity 在SecondActivity中,写一个静态方法actionStart() public static void actionStart( ...
- Activity启动活动最佳写法
一,在被启动的Activity中新加一个静态方法public static void actionStart(Context context, String data1, String data2) ...
- android: SQLite 数据库的最佳实践
6.5.1 使用事务 前面我们已经知道,SQLite 数据库是支持事务的,事务的特性可以保证让某一系列的操 作要么全部完成,要么一个都不会完成.那么在什么情况下才需要使用事务呢?想象以下场 景, ...
- (Android第一行代码实验一)活动的最佳实践
活动的最佳实践 1.知晓当前是在哪一个活动 这个技巧将教会你,如何根据程序当前的界面就能判断出这是哪一个活动. 首先需要新建一个 BaseActivity 继承自 Activi ...
- android:活动的最佳实践
2.6.1 知晓当前是在哪一个活动 这个技巧将教会你,如何根据程序当前的界面就能判断出这是哪一个活动.可能你会觉 得挺纳闷的,我自己写的代码怎么会不知道这是哪一个活动呢?很不幸的是,在你真正进入 ...
随机推荐
- atitit查询表修改表字段没反应--解锁锁定的表
atitit查询表修改表字段没反应--解锁锁定的表 查询表修改表字段没反应 要是使用gui 没反应,最好使用cmd 方式,不卉不个gui 锁上.. ALTER TABLE t_mb_awardweix ...
- paip.php 5.0 5.3 5.4 5.5 -6.0的新特性总结与比较
paip.php 5.0 5.3 5.4 5.5 -6.0的新特性总结与比较 PHP5的新特性 2 · 对象的参照过渡是默认的(default) 3 · 引入访问属性的限制 3 · 引入访问方法的限 ...
- Javascript中String对象的的简单学习
第十一课String对象介绍1:属性 在javascript中可以用单引号,或者双引号括起来的一个字符当作 一个字符对象的实例,所以可以在某个字符串后再加上.去调用String 对象 ...
- CSS3实践之路(六):CSS3的过渡效果(transition)与动画(animation)
刚开始W3C CSS Workgroup拒绝将CSS3 transition与animation加入官方标准,一些成员认为过渡效果和动画并非样式属性,而且已经可以用脚本实现.所以请大家明白,特别是We ...
- Android Studio使用小技巧:提取方法代码片段
http://www.jb51.net/article/65510.htm 今天来给大家介绍一个非常有用的Studio Tips,有些时候我们在一个方法内部写了过多的代码,然后想要把一些代码提取出来再 ...
- 新版PHP 7效能實測:Drupal 7能快70%,碎形計算大勝Ruby和Python
PHP 7才剛在12月3日正式釋出,網頁開發框架Zend公司立刻發表了一份PHP新舊版效能大車拼報告,除了PHP 7和PHP 5.6之外,也把HHVM 3.7版納入一起比較. Zend公司選擇了幾套知 ...
- [算法导论]二叉查找树的实现 @ Python
<算法导论>第三版的BST(二叉查找树)的实现: class Tree: def __init__(self): self.root = None # Definition for a b ...
- GDAL 遥感图像处理后的数据保存为图像文件的实现方法
在遥感图像处理中,GDAL库不仅能读取和处理大部分的遥感图像数据,而且还能够实现图像处理后将数据保存为图像的功能. 本文就详细介绍如何将内存中的图像数据保存为.tif格式. 首先,遥感数据处理完,保存 ...
- IntelliJ IDEA + Maven环境编写第一个hadoop程序
1. 新建IntelliJ下的maven项目 点击File->New->Project,在弹出的对话框中选择Maven,JDK选择你自己安装的版本,点击Next 2. 填写Maven的Gr ...
- Codeforces Round #379 (Div. 2) C. Anton and Making Potions 枚举+二分
C. Anton and Making Potions 题目连接: http://codeforces.com/contest/734/problem/C Description Anton is p ...