惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Last Watchdog
The Last Watchdog
量子位
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
GbyAI
GbyAI
雷峰网
雷峰网
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
V
Visual Studio Blog
C
Check Point Blog
爱范儿
爱范儿
罗磊的独立博客
Engineering at Meta
Engineering at Meta
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
小众软件
小众软件
H
Help Net Security
B
Blog
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 叶小钗
B
Blog RSS Feed
Cisco Talos Blog
Cisco Talos Blog
S
Schneier on Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tor Project blog
TaoSecurity Blog
TaoSecurity Blog
Scott Helme
Scott Helme
AI
AI
D
DataBreaches.Net
Simon Willison's Weblog
Simon Willison's Weblog
V
Vulnerabilities – Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
Lohrmann on Cybersecurity
C
CERT Recently Published Vulnerability Notes
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Last Week in AI
Last Week in AI
T
Threatpost
Y
Y Combinator Blog
Martin Fowler
Martin Fowler
Know Your Adversary
Know Your Adversary
T
Tailwind CSS Blog
N
News and Events Feed by Topic
N
News and Events Feed by Topic
The Hacker News
The Hacker News
P
Proofpoint News Feed

土土哥的Blog

好久没有更新博客=。= 阿里巴巴国际无线技术部 - 招人啦~求iOS、Android、Java 转-阿里巴巴国际无线技术部 - 在这里遇见最好的自己 反编译分析并模拟实现methodSignatureForSelector方法 反编译分析Xcode8的Bug, release下连续两次调用有二级指针参数的空方法会Crash 有趣的Autolayout示例5-Masonry实现 在对象dealloc的后期执行Task-开源库TTGDeallocTaskHelper 用QuartzCode快速实现一个收藏动画 开源项目-拼图验证控件TTGPuzzleVerify的实现 Swift开源Mac App - BingWallPaper 有趣的Autolayout示例4-Masonry实现 翻译-为什么objc_msgSend必须用汇编实现 API返回结果设计经验与总结 结合访问Out Parameters出现EXC_BAD_ACCESS的例子,反编译汇编解读__autoreleasing 总结一些iOS项目中组织代码的方法 对组件化与模块化的思考与总结 开源项目-TTGTagCollectionView 有趣的Autolayout示例3-Masonry实现 Swift开源项目: TTGEmojiRate的实现 Swift写的库-TTGSnackbar 有趣的Autolayout示例2-Masonry实现 解决iOS项目的版本兼容问题-结合宏、Category和Runtime 用Runtime的手段填充任意NSObject对象的nil属性 有趣的Autolayout示例-Masonry实现 UITextView编辑时插入自定义表情-续-自定义表情图片的大小 RPC框架Thrift例子-PHP调用C++后端程序 GCD使用经验与技巧浅谈 为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权 Enum-枚举的正确使用-Effective-Objective-C-读书笔记-Item-5 @autoreleasepool-内存的分配与释放 有关宏定义的经验与技巧-简化代码-增强Log Effective-Objective-C-读书笔记-Item-4-如何正确定义常量 UITextView编辑时插入自定义表情-简单的图文混编 关于评论不见了=。= Entity和Model的不同-关于代码的数据层 一次审核被拒的经历-关于iCloud到底应该备份什么数据 Block类型变量-缓存Http请求与回调 提升UITableView性能-复杂页面的优化 NSString的Copy与内存分配 利用NSProxy实现消息转发-模块化的网络接口层设计-原创 Effective-Objective-C-读书笔记-Item-3 Effective-Objective-C-读书笔记-Item-1 iOS项目的目录结构-原创 Android开源库-LinkTextView-原创 第一篇Blog
Effective-Objective-C-读书笔记-Item-2
土土哥 · 2015-02-06 · via 土土哥的Blog

前言

第二弹来了。

这一节讲的是尽量在一个头文件中减少其它头文件的引入。

头文件

Objective-C和C语言、C++很像,都将类的实现与声明分开,用.h后缀名文件表示声明文件,用.m文件实现类。当要用到这个类的时候,只需要引入头文件即可,至于编译器、运行时是如何知道头文件里面的类对应的实现在哪里,在这了不做说明。一下用例子说明,先看看下面的类:

1
2
3
4
5
6
7
8

#import <Foundation/Foundation.h>


@interface Wheel : NSObject
@property(copy, nonatomic) NSString *manufacturer;
@property(assign, nonatomic) NSUInteger radius;
@end

第二个类

1
2
3
4
5
6
7
8

#import <Foundation/Foundation.h>


@interface Engine : NSObject
@property(copy, nonatomic) NSString *manufacturer;
@property(assign, nonatomic) NSUInteger power;
@end

然后就是车类Car:

1
2
3
4
5
6
7
8

#import <Foundation/Foundation.h>


@interface Car : NSObject
@property(strong, nonatomic) Wheel *wheel;
@property(strong, nonatomic) Engine *engine;
@end

注意到少了什么东西没有?
是的,写过C语言、C++的童鞋一下就能发现,Car类没有引入Engine和Wheel的头文件,肯定会编译出错的,因为编译器不知道Engine、Wheel类是啥。
那好,我们加上下面两行:

1
2
#import "Wheel.h"
#import "Engine.h"

嗯。这样就不会出错了。但是这样真的好吗?Objective-C给我们提供了@class关键字,就是来解决这个问题的。

前置声明(forward declaration)

何为前置声明?看看下面的Car类的头文件例子。

1
2
3
4
5
6
7
8
9
10
11

#import <Foundation/Foundation.h>


@class Wheel;
@class Engine;

@interface Car : NSObject
@property(strong, nonatomic) Wheel *wheel;
@property(strong, nonatomic) Engine *engine;
@end

@class就是类的前置声明(forward declaration),就是告诉编译器“嗨,不用找了,Wheel类和Engine类是肯定存在的,用到的时候再找”。有了前置声明,我们就不用显式的引入Wheel类和Engine类了。

当然,在Car类的实现文件.m文件中,我们还是要显式的引入Wheel和Engine类的,因为在这里我们要具体用到这两个类了,当然要知道类的细节。

为何不要import?

为什么不直接import呢?因为如果直接用import引入Wheel和Engine的声明,那么任何import引入了Car类的文件,也同时会引入Wheel、Engine类的声明,而且最终我们可能并不一定会直接跟Wheel、Engine类打交道,这样不就引入了“没有用”的类了吗?而且这样做很可能造成文件引入成“环”。

虽然import可以避免重复声明造成编译出错,传统的C语言、C++在声明的时候也可以通过如下方式避免重复声明:

1
2
3
4
5
6
#ifndef _WHEEL_H_
#define _WHEEL_H_



#endif

但是既然Objective-C有@class这种前置声明的办法,为何不用呢。

必须用import的时候

当然,@class这样的前置声明并不能解决一切头文件引入的问题,如下这样的类,就必须要用import:

1
2
3
4
5
6
7
8
9
10
#import <Foundation/Foundation.h>


#import "Car.h"


#import "Driver.h"

@interface BigCar : Car <Driver>
@end

是的,当类需要被继承、定义的protocol需要实现的时候,就需要import相关的头文件了(protocol的实现如果跟类的使用者没有关联,可以定义在类的实现文件中的“扩展category”中),当然,还有@protocol这样的protocol的前置声明,怎么用就留给读者自己查阅相关资料了。

总结

大费周章的讲了这么多,其实目的就是一个:尽量少在头文件里面引入其他头文件。

最终的目的就是只暴露最少的细节

写代码有段时间了,一直都在琢磨这句话,希望读者也能好好体会~