转自:http://marshal.easymorse.com/tech/objc-%e6%ba%90%e6%96%87%e4%bb%b6%e7%9a%84%e7%bb%84%e7%bb%87

最简单的ObjC程序,你都可以这样写:

#import <Foundation/Foundation.h>

@interface Book : NSObject{

}

-(NSString *) getPrice;

@end

@implementation Book

-(NSString *) getPrice{
return @"$17";
}

@end

int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

Book *book=[[Book alloc] init];
NSLog(@"Book price: %@",[book getPrice]);
[pool drain];
return 0;
}

理论上讲,按照上面的写法,你可以把所有的代码都写在一个文件里。

但是问题是,你不便于维护这个代码。代码很长,很乱。

所以,一般有以下几种形式来拆分和组织代码:

  • 类文件拆分为头文件和m文件
  • 使用组的概念来管理文件

拆分接口和实现部分

拆分h文件和m文件很好理解。只要使用Xcode做开发,通过向导页面创建类,文件默认情况下就是强制分开的:

使用组的概念管理文件

使用组的概念。在Xcode下面,程序源文件都是放在Source目录下的,在该目录下,可以进一步创建“目录”,把不同用途的源文件分类放置。这样就如同桌上凌乱的书归置到书架里一样。很好查找和查阅。

可以看到,下面是把Book相关的一些类放在book组中了。

这个组看起来是目录,但如果你打开finder,查看目录结构,发现并不存在这样的目录:

拆分文件带来的问题及解决办法

拆分文件带来很多好处。不只是自己看着方便了,还能方便多人合作开发。如果多人修改一个文件,很容易出现各种问题。每个人负责自己的代码文件,这些文件组成一个项目,这样就不容易造成文件版本上的冲突。

但是,这也带来了新的问题。一个文件依赖另外一个文件的时候,需要通过import来导入。比如:

#import <Foundation/Foundation.h>
#import "CategoryDemo.h"
#import "Book.h"
#import "MusicBook.h"
#import "PlayMusic.h"

@class Author;

int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSString *message=@"你好,世界!";
NSLog(@"%@, 长度为: %i",message,[message length]);
[message printHelloInfo];

Book *book=[[Book alloc] init];

这里main方法中使用了Book类,那么,就需要通过import把它引进来,否则,编译器不知道Book类在哪里。

另外,如果我这样:

#import <Foundation/Foundation.h>
#import "CategoryDemo.h"
//#import "Book.h"
#import "MusicBook.h"
#import "PlayMusic.h"

@class Author;

int main (int argc, const char * argv[]) {

注释了对Book头文件的导入,系统一样编译通过,而且运行正常。这是怎么回事儿呢?

这是因为编译器很聪明。它发现MusicBook头文件里面已经导入了Book头文件:

#import <Cocoa/Cocoa.h>
#import "Book.h"
#import "PlayMusic.h"

@interface MusicBook : Book <PlayMusic>{

在上面代码中有一个奇怪的代码:

@class Author;

有了这句话,该代码中的:

book.author=[[Author alloc]init];

就不会报错了。

可以用下面的语句替代@class的代码:

#import "Author.h"
//@class Author;

系统一样会很好的工作。那么,@class和#import有什么区别呢?

这里要说一下头文件依赖关系。如果有100个m文件都导入了某个头文件,那么,当这个头文件改变了内容,则编译器会强制重新编译这100个m文件的。编译的速度可想而知。

@class就是为了避免这样的事情发生的。当编译器看到比如类文件B是通过@class的方式引入一个类文件A,就不会在该类文件A的头文件改动后重新编译B了。

那如果这样,都用@class替代#import吧。问题是,有些情况,只能使用#import。因为有时候编译器不只是需要知道类B引用到类A,还需要知道类A的内部信息,而这些信息是类B需要的。比如类B继承自类A,这时就不能用@class,而只能用#import。

ObjC: 源文件的组织的更多相关文章

  1. “前.NET Core时代”如何实现跨平台代码重用 ——源文件重用

    微软在2002年推出了第一个版本的 .NET Framework,这是一个主要面向Windows 桌面(Windows Forms)和服务器(ASP.NET Web Forms)的基础框架.在此之后, ...

  2. Google软件构建工具Bazel FAQ

    Google软件构建工具Bazel FAQ 本文是我的翻译,原文在这里.欢迎转载,转载请注名本文作者和原始链接 注:如果想了解Bazel的原理,可以看看我之前翻译的Google Blaze原理及使用方 ...

  3. C++生成二级制文件过程(预处理->编译->链接 )

    转载请注明出处 Windows下C++编程,通过VC生成工程,编写C++源文件,点运行,代码没问题直接出结果.VC什么都帮我们搞了,不了解其中过程也完全没问题. 转到linux下写c++,总觉得有点虚 ...

  4. Google软件构建工具Bazel

    转载Google软件构建工具Bazel FAQ 本文是我的翻译,原文在这里.欢迎转载,转载请注名本文作者和原始链接注:如果想了解Bazel的原理,可以看看我之前翻译的Google Blaze原理及使用 ...

  5. .NET Core跨平台的奥秘[中篇]:复用之殇

    在<.NET Core跨平台的奥秘[上篇]:历史的枷锁>中我们谈到:由于.NET是建立在CLI这一标准的规范之上,所以它天生就具有了"跨平台"的基因.在微软发布了第一个 ...

  6. Objective-C 基础教程第六章,源文件组织

    目录 Object-C 基础教程第六章,源文件组织 0x00:前言 0x01:Xcode创建OC类 0x02:Xcode群组 0x03 Xcode跨文件依赖关系 @class关键字 导入和继承 小结 ...

  7. 明白python文件如何组织,理解建立源文件

    在Python 中引用是非常简单的事情,这里需要清楚三个概念就可以了包.模块.类.类这个就不用说了. 模块对应的是一个.py 文件,那么module_name 就是这个文件去掉.py 之后的文件名,p ...

  8. 【转】开篇python--明白python文件如何组织,理解建立源文件

    在Python 中引用是非常简单的事情,这里需要清楚三个概念就可以了包.模块.类.类这个就不用说了. 模块对应的是一个.py 文件,那么module_name 就是这个文件去掉.py 之后的文件名,p ...

  9. @OBJC 和 DYNAMIC

    原文转载自:@OBJC 和 DYNAMIC 虽然说 Swift 语言的初衷是希望能摆脱 Objective-C 的沉重的历史包袱和约束,但是不可否认的是经过了二十多年的洗礼,Cocoa 框架早就烙上了 ...

随机推荐

  1. MySQL 官方测试库

    MySQL 官方测试库 github 地址 https://github.com/datacharmer/test_db MySQL 文档地址 https://dev.mysql.com/doc/em ...

  2. CentOS7 开放端口 通过 firewall-cmd 工具来操作防火墙

    CentOS7 提供了 firewall-cmd 工具来操作防火墙. firewall-cmd --permanent:表示设置为持久,配置被写入配置文件,跨重启,不会立即生效,重新加载配置后生效.不 ...

  3. 2-开发共享版APP(搭建指南)-修改包名

    https://www.cnblogs.com/yangfengwu/p/11273734.html https://www.cnblogs.com/yangfengwu/p/11273746.htm ...

  4. [RN] React Native 下拉放大动画

    React Native 下拉放大动画 经测试,无法运行 https://www.jianshu.com/p/1c960ad75020

  5. 洛谷P1230智力大冲浪 题解

    题目描述 小伟报名参加中央电视台的智力大冲浪节目.本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者m元.先不要太高兴!因为这些钱还不一定都是你的?!接下来主持人宣布了比赛规则: ...

  6. ES6解构赋值常见用法

    解构赋值出现的契机: let obj = { a: 1, b: 2 } // 取值 let a = obj.a let b = obj.b 问题核心: 每次取值既要确定对象属性名,还得重新定义一个变量 ...

  7. Python语言基础考察点:python语言基础常见考题(一)

    一.python是静态还是动态类型?是强类型还是弱类型? 1.动态强类型语言(不少人误以为是弱类型) 不要傻傻分不清 2.动态还是静态指的是编译期还是运行期确定类型 3.强类型指的是不会发生隐式类型转 ...

  8. Scala反射(二)

    我们知道,scala编译器会将scala代码编译成JVM字节码,编译过程中会擦除scala特有的一些类型信息,在scala-2.10以前,只能在scala中利用java的反射机制,但是通过java反射 ...

  9. word2vec学习总结

    目录 1.简介 2.从统计语言模型开始 2.1序列概率模型 2.2 N元统计模型 3.深度序列模型 3.1神经概率模型 3.2 one-hot向量表示法 3.3 word2vec 3.4word2ve ...

  10. WebBrowser内存泄露

    使用WebBrowser控件开发的程序,占用内存会随着时间不停增长,最终内存溢出导致崩溃.究其原因是由于其自身的缺陷造成的.每一次加载新页面,WebBrowser就会多占用10-20M内存,有资料说是 ...