[Cocoa]深入浅出 Cocoa 之 Framework
罗朝辉(http://blog.csdn.net/kesalin/)
CC许可,转载请注明出处

Framework 简介

Mac OS X 扩展了 framework 的功能,让我们能够利用它来共享代码和资源。framework 在概念上有点像 Window 下的库,但是比库更加强大,通过 framework 我们可以共享所有形式的资源,如动态共享库,nib 文件,图像字符资源以及文档等。系统会在需要的时候将 framework 载入内存中,多个应用程序可以同时使用同一个 framework,而内存中的拷贝只有一份。一个 framework 同时也是一个 bundle,我们可以在 finder 里浏览其内容,也可以在代码中通过 NSBundle 访问它。利用 framework 我们可以实现动态或静态库的功能。与动态/静态库相比,framework 有如下优势:

第一,framework 能将不同类型的资源打包在一起,使之易于安装,卸载与定位;
第二,framework 能够进行版本管理,这使得 framework 能不断更新并向后兼容;
第三,在同一时间,即使有多个应用程序使用同一 framework,但在内存中只有一份 framework 只读资源的拷贝,这减少了对内存的占用

Framework 的结构

下面是一个带有A,B两个版本和一个 resources 目录的 framework 结构,并设定当前版本为 B:

[cpp] view plaincopyprint?
  1. MyFramework.framework/
  2. Headers      -> Versions/Current/Headers
  3. MyFramework  -> Versions/Current/MyFramework
  4. Resources    -> Versions/Current/Resources
  5. Versions/
  6. A/
  7. Headers/
  8. MyHeader.h
  9. MyFramework
  10. Resources/
  11. English.lproj/
  12. Documentation
  13. InfoPlist.strings
  14. Info.plist
  15. B/
  16. Headers/
  17. MyHeader.h
  18. MyFramework
  19. Resources/
  20. English.lproj/
  21. Documentation
  22. InfoPlist.strings
  23. Info.plist
  24. Current  -> B

结合上面的结构,下面我们来看本例中 ExampleFramework 的结构图:

Framework 存放位置
在 Mac OS 中有三个级别的位置来存放 framework。一般我们自己编写的 framework 都应该是应用程序级别。
1,系统级,/Library/Frameworks,放置到该级别,这需要管理员权限,整个系统都可以共享使用该级别的 framework;
2,用户级,/Users/用户名/Library/Frameworks,拥有用户权限的应用程序都可以共享使用该级别的 framework;
3,应用程序级。

在应用程序中内嵌 Framework

1,创建 Framework
新建一个名为 FrameworkDemo 的 Cocoa application 工程,然后选中项目名,向其中添加名为 ExampleFramework  的 Cocoa Framework。

2,添加内容
向 Framework 中添加源代码(请下载源代码),并导出需要向外部公开的头文件。

导出头文件有一些技巧:
1,如果有我们不想向用户公开的类名出现在必须公开的头文件中,我们可以使用 id 替代该类名或使用 @class 前置申明来避免导出该类的头文件,在本例中使用 id 替代 InternalObject,从而避免导出 InternalObject 类的头文件。
2,如果需要导出多个头文件,常见的做法是新建一个与 framework 同名的 .h 文件,将需要导出的头文件包含到该头文件中来。如本例中的  ExampleFramework.h。

3,修改 framework build 选项
我们在使用自己编写的库时,常碰到下面的编译错误:

[cpp] view plaincopyprint?
  1. Library not loaded: path/to/framework
  2. Referenced from: path/to/app/
  3. Reason: image not found

这多半是由于 framework 的 Installation Directory 编译选项设置不正确,导致应用程序无法正确定位 framework 所致。这需要我们设置编译选项 Installation Directory 为 @executable_path/../Frameworks。

4,使用 framework
至此,framework 编写完成,下面我们来在 FrameworkDemo 中来使用它。首先我们需要将 ExampleFramework 导入到 FrameworkDemo 中来,这样 FrameworkDemo 在运行时才能定位该 framework。新建一个 Add copy files 型的 build phase,设置其 destination 为 framework,加入已经编写好的 ExampleFramework。

导入 framework 之后,我们就可以在工程中使用该 framework 了。编写如下代码:

[cpp] view plaincopyprint?
  1. //
  2. //  FrameworkDemoAppDelegate.m
  3. //  FrameworkDemo
  4. //
  5. //  Created by kesalin on 11-10-16.
  6. //  Copyright 2011年 kesalin@gmail.com. All rights reserved.
  7. //
  8. #import "FrameworkDemoAppDelegate.h"
  9. <span style="color:#ff6666;"><strong>#import <ExampleFramework/ExampleFramework.h></strong></span>
  10. @implementation FrameworkDemoAppDelegate
  11. @synthesize window;
  12. - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
  13. {
  14. <span style="color:#cc9933;">        EntityObjectA *objectA = [[EntityObjectA alloc] init];
  15. EntityObjectB *objectB = [[EntityObjectB alloc] init];
  16. NSLog(@"Object A called: %@", [objectA methodOne]);
  17. NSLog(@"Object B called: %@", [objectA methodTwo]);
  18. NSLog(@"Object B called: %@", [objectB methodOne]);
  19. NSLog(@"Object B called: %@", [objectB methodTwo]);</span>
  20. }
  21. @end

注意:我们使用 framework 的方式为 :framework名/framework名.h,这是约定的常规做法,Cocoa 自带的 framework 也都遵守这一约定,所以我们自己编写的库最后也遵守这一约定。

5,编译运行
至此,工作完成,编译运行,应当输出如下:

[cpp] view plaincopyprint?
  1. Object A called: EntityObjectA:methodOne
  2. Object B called: EntityObjectA:methodTwo - InternalObject:description
  3. Object B called: EntityObjectB:methodOne
  4. Object B called: EntityObjectB:methodTwo - InternalObject:description

6,清除冗余文件
这时可选项,且只对使用内嵌 framework 的应用程序有效。当我们拷贝导入 framework 之后,应用程序 bundle 已经拷贝了一份 framework,那么原本编译生成的那一份 framework就变得多余了,我们可以将其清理掉。在使用内嵌 framework 的应用程序的 build phases 中加入 run script phase,脚本内容如下:

[cpp] view plaincopyprint?
  1. echo "build path ${TARGET_BUILD_DIR}"
  2. cd ${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}/Contents/Frameworks
  3. rm -rf */Headers
  4. rm -rf */Versions/*/Headers
  5. rm -rf */Versions/*/PrivateHeaders
  6. rm -rf */Versions/*/Resources/*/Contents/Headers

使用外部 framework

上面的示例是在应用程序内嵌 framework,供应用程序本身使用,很多时候,我们是使用第三方编写的 framework,下面接着来演示如何将 ExampleFramework 当做外部framework。
1,新建名为 TestExampleFramework 的 Cocoa Application 程序,在 TestExampleFrameworkAppDelegate.m 中添加如上步骤 4 中使用 framework 的代码。

2,编译运行,这时会报找不到头文件,类名的错误。这时因为我们还没有导入framework。在 Build Phase 的 Link Binary With Libraries 中加入生成好的 ExampleFramework,该 framework 的默认生成路径在: /用户名/Library/Developer/XCode/DerivedData/FrameworkDemo-XXXX/Build/Products/Debug/下。至此,编译运行,输出应当如上步骤 5 相同。

此外还有一种方式使用第三方 framework,如果我们拥有第三方 framework 的源代码工程,想在我们的工程中编译该 framework,并使用它。我们可以将第三方 framework 的工程文件加入我们自己的工程,并在 Target Dependencies 和 Link Binary With Libraires 加入第三方 framework,这样我们就可以使用该 framework了。如下图所示:

详解Framework相关推荐

  1. zend framework php编码规范,Zend Framework常用校验器详解

    本文实例讲述了Zend Framework常用校验器.分享给大家供大家参考,具体如下: Date日期校验器 代码:<?php require_once 'Zend/Validate/Date.p ...

  2. 【配置映射】—Entity Framework实例详解

    前两篇博文中的配置属性和配置关系都是配置映射,配置属性是属性的映射,配置关系式关系的映射,本篇从讲讲实体的映射. 首先,配置实体映射到表,使用ToTable方法,它接受两个参数,第一个参数是表的名称, ...

  3. 【查询】—Entity Framework实例详解

    Entity Framework 查询使用集成查询,简称LINQ.LINQ是一个查询框架,并不限于Entity Framework使用,同样不限于数据库.LINQ Provider 负责将LINQ查询 ...

  4. Android Framework系统服务详解

    Android Framework系统服务详解 操作环境 系统:Linux (Ubuntu 12.04) 平台:高通 Android版本:5.1 PS: 符号...为省略N条代码 一.大致原理分析 A ...

  5. java集合框架的结构_集合框架(Collections Framework)详解及代码示例

    简介 集合和数组的区别: 数组存储基础数据类型,且每一个数组都只能存储一种数据类型的数据,空间不可变. 集合存储对象,一个集合中可以存储多种类型的对象.空间可变. 严格地说,集合是存储对象的引用,每个 ...

  6. Django REST FRAMEWORK swagger(一)框架详解

    Django REST FRAMEWORK swagger(一.框架详解) 一.Django REST  SWAGGER框架图 具体见下图 二.说明 RESTFul说明 每一个URI代表一种资源: 客 ...

  7. 【配置属性】—Entity Framework实例详解

    Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...

  8. Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(一)

    文章大纲 引言 一.Android Storage Access Framework 二.Storage Access Framework 的主要角色成员 1.Document Provider 文件 ...

  9. Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(二)

    文章大纲 引言 一.DirectFragment 1.当选中DirectoryFragment中RecyclerView的Item时 2.选中DirectoryFragment中RecyclerVie ...

最新文章

  1. 最通俗的机器学习介绍
  2. SQL Server查看错误日志存档编号及其详情
  3. leetcode 206 Reverse Linked List
  4. 适合自学python的图书-清华学霸整理,Python入门到精通这几本书帮你快速入行
  5. CCF 2018年题目题解 - Python
  6. MyBatis-20MyBatis高级结果映射【一对一映射(4种方式)】
  7. kvm虚拟机设置万兆网卡_SR-IOV 10Gb 万兆网卡支持
  8. 《MySQL 8.0.22执行器源码分析(3.1)关于RowIterator》
  9. JS调用后台方法大全
  10. ffmpeg-filter 入门
  11. 数据结构与算法LeetCode题目记录
  12. matlab 换热器仿真,基于MATLAB的换热器温度控制仿真研究.doc
  13. java类中serialVersionUID的作用
  14. ps还原上一步快捷键,ps返回上一步快捷键是什么
  15. ZBrush与数位板雕刻模型如何才能结合
  16. LearnGL - 13 - PointLight - 点光源
  17. 提前和2022年6月的自己聊聊
  18. 支付宝手机网站支付详细流程步骤
  19. 【超好玩的路由环路系列】2——汇总环路
  20. 如何删除映射网络驱动器

热门文章

  1. android git提交整个项目_使用子模块和子树来管理 Git 项目 | Linux 中国
  2. hashCode() 和equals() 区别和作用
  3. mysql 查询优化 Explain关键字 高性能mysql笔记
  4. 为了OFFER而战,大四那些日子在牛客网和Leetcode刷SQL题目
  5. python中frameset中的元素怎么识别_python3.6+selenium实现操作Frame中的页面元素
  6. 科研实习 | 北京大学智能学院贺笛老师招收NLP/GNN方向科研实习生
  7. 北京招聘 | 澜舟科技招聘NLP工程师、NLP研究员、产品项目经理
  8. 开放域知识库问答研究回顾
  9. 直播 | 旷视研究院最新理论成果:批归一化和权重衰减的球面优化机制
  10. 综述 | 知识图谱向量化表示