转自: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. tomcat相关知识点

    Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用. tomcat的文件结构: bin:用于存放启动和关闭tom ...

  2. struts2学习1

    struts2使用优势 自动封装参数 参数校验 结果的处理(转发|重定向) 国际化 显示等待页面 表单的防止重复提交 struts2具有更加先进的架构以及思想 使用拦截器 struts2的历史 str ...

  3. EXCEPTION_HIJACK(0xe0434f4e)异常的抛出过程

    样例工程 在VS2013里新建一个C#控制台工程,写下如下代码: using System; using System.Collections.Generic; using System.Linq; ...

  4. 几款不错的java表达式引擎

    mvel 比较老牌了,很强大,但是好久没更新了 参考地址: http://mvel.documentnode.com/ https://github.com/mvel/mvel ScriptEngin ...

  5. [ZJJOI2013]K大数查询 整体二分

    [ZJJOI2013]K大数查询 链接 luogu 思路 整体二分. 代码 #include <bits/stdc++.h> #define ll long long using name ...

  6. Web项目中使用Log4net 案例

    简介: 几乎所有的大型应用都会有自己的用于跟踪调试的API.因为一旦程序被部署以后,就不太可能再利用专门的调试工具了.然而一个管理员可能需要有一套强大的日志系统来诊断和修复配置上的问题. 经验表明,日 ...

  7. python总结一

    1. python中的而标准数据类型: number(数字) string(字符串) list(列表) tuple(元祖) dic(字典) 其中数字类型有: python支持四种不同的数字类型: in ...

  8. base64和Blob互相转换

      1.base64转blob(二进制数据) /** * 将以base64的图片url数据转换为Blob * @param urlData 用url方式表示的base64图片数据 */ functio ...

  9. Android Studio 之 ROM【2】, LiveData+ViewModel+AsyncTask+Repository

    改造上一节 ROM[1], 1.利用 LiveData<List<Word>> 与 observe 中的 onChanged 配合,删除掉之前的textView更新函数(upd ...

  10. C# 获得本地通用网卡信息

    可以通过使用命名空间下的ManagementObjectSearcher类及其方法Get来获得通用网卡信息. 其中,最重要的是ManagementObjectSearcher构造函数的输入参数,可以传 ...