react native是前端吗 是 swif 还是objectc

swift资讯列表 - ITeye资讯频道
资讯月刊下载
第116期(17-10)
20个非常有用的Java程序片段
互联网高可用架构技术实践
第115期(17-09)
Java 9 正式发布,终落地 Jigsaw 项目
一个真实的DevOps演进过程是啥样的?
第114期(17-08)
Spring思维导图,让Spring不再难懂(aop篇)
正确认识Docker、Kubernetes 、Apache Mesos
引用原文:Swift with a hundred engineers 翻译: Vincent 本文出自Uber移动架构和框架组负责人托马斯·阿特曼于2016年在湾区Swift峰会上的演讲,分享了使用Swfit重写Uber的好与坏。以下为译文: 我是托马斯·阿特曼,目前是Uber移动架构和框架组负责人。Uber现在的用户量已经达到数百万,这么大的用户量,Uber是如何用框架实现的呢? Swift与百 ...
苹果对于 Swift Server 端的发力让诸多服务端框架应运而生,而由位于加拿大多伦多的 PerfectlySoft Inc. 公司研发推出的 Swift 服务端开源框架 Perfect 自开源以来便颇受开发者们喜爱,比如来自去哪儿网的团队便基于 Perfect 完成了一套 RESTful API 的开发。今天,PerfectlySoft 总裁尚·史蒂芬斯为我们带来了关于 Perfect 的最新 ...
本月 Swift 首次进入 TIOBE 排行版前 10 名。Swift 是一种新的编程语言,用于编写 iOS 和 OS X 应用。Swift 结合了 C 和 Objective-C 的优点并且不受C兼容性的限制。Swift 采用安全的编程模式并添加了很多新特性,这将使编程更简单,更灵活,也更有趣。 3 年前苹果宣布用 Swift 代替移动应用程序开发语言 Objective-C,但因 Objecti ...
引用作者简介: 何轶琛,去哪儿网 iOS 开发工程师,四年多 iOS 应用开发经验,在去哪儿网实践了 Realm、Cocoapods、React Native 等一些好用、有用的技术,目前主要精力在 Swift 上。 责编:唐小引,技术之路,共同进步。欢迎技术投稿、给文章纠错,请发送邮件至。 声明: 本文为《程序员》原创文章,未经允许请勿转载,更多精彩文章请订阅 201 ...
作为移动开发者,我们除了搞定日常工作之外,有时也需要睁眼看世界——了解自己身边发生了哪些变化又出现了哪些趋势。这不仅能够为我们提供宝贵的知识以解决当前技术问题,同时亦能够更为确切地把握用户希望从最新移动应用中得到的理想体验。 那么,2016年到底给我们带来了哪些启示?下面来看六条移动应用相关开发趋势。
安全性 安全在今年的移动开发领域一直拥有极高热度。而苹果与FBI之间的激烈冲突也再次强调了保护用 ...
ShiftJS,这是一款将 Swift 代码转换为友好的 JavaScript 代码的编译器,即 Swift to JavaScript Transpiler,使用 JavaScript 编写,其主要贡献者为来自纽约的软件开发者Donald Steinert,该项目目前仍处于早期开发阶段。 使用 ShiftJS 很简单,安装:
npm install shift.js
Getting Start ...
当我们提到代码崩坏(code breaking)时,一般是指下面这两种情况。 语音语义发生了变化。这时你需要重构代码,典型例子就是 Swift 从 (…, $NSError) -& Result? 格式改为错误抛出。 语言语法发生了变化。这时只需进行迁移,然后大部分代码或多或少都能自动修复(还有一小部分需要微调)。 后者确实会带来一些麻烦,但更具破坏性的是前者。如果我猜的没错,Swift 3
相对于Objective-C,Swift是一种编译代码时速度更快、安全性与可靠性更高、同时具有可预测性的语言。下面我们列出了在实践中使用这种新语言时,所获取一些Swift使用技巧。这些技巧有助于让开发者编写出更干净的代码,并能帮助更熟悉Objective-C的程序员适应Swift编程,同时适用于在Swift上具有各种背景经历的人,请继续往下看。 章节的顺序是按照使用者对Swift的熟悉程度来排列的。 ...
作者: David Ungar 翻译:BigNerdCoding 原文链接 前言 伴随着Swift语言的快速发展,我们对于苹果设备编程的认识也发生着变化。与原来的Objective-C语言相比,Swift语言带来的更多现代化的特征,例如函数式编程和更多的类型检查。 Swift语言采用一些安全的编程模式来帮助开发者避免一些bug。然而不可避免的是,这种雄心勃勃的做法也会让我们的程序中引入一些陷阱(至少 ...
Swift 中的协议如果需要泛型化,可以通过抽象类型成员的方式实现,而不是在参数类型上做文章。至此,协议本身可以不再被当成是一个类型,而是看做一个通用的约束。英文原文 问题 如果你曾将一个泛型协议当做类型使用:
protocol GenericProtocol { typealias AbstractType func magic() -& AbstractType } let list : ...
2015 年 12 月 3 日,Swift 正式开源。同时,官方也公布了 Swift 3 的最新消息,即 Swift 3 将会在 2016 年秋天发布。 API 设计指南与 Swift 中 Objective-C 的导入 Swift 3 的 API 设计指南将与 Objective-C 中 Cocoa 的完全不同。这就意味着 Objective-C 中的 API 映射到 Swift 时会与以往不同。 ...
从Swift中使用LLVM是件很美妙的事情。它给了我们一个非常好的机会—在Swift中借助LLVM来编写语言。本文主要演示如何在Swift中使用LLVM。 本文主要内容是演示如何在Swift中使用LLVM,其包含了如下四个要点: 获取最新版本的LLVM 使用CMake和llvm-config编译程序 编写简单的Swift程序,编译并与LLVM进行连接 在内存中编写简单的sum函数并使用LLVM编译器 ...
确切地讲,我是30天前开始学习swift的。3天前,我开发的第一个应用程序通过了苹果公司的审核。相比其他事情,这一开发过程并不算什么,但是对我而言,却是一个巨大的成就。 我没有计算机的学位,也没有专业的开发经验,但是在过去的5年中,我一直在一个开发团队中担任产品经理。因为兴趣,曾经也用Ruby写过一些Rails应用。我一直想和我的工作有一个更直接的联系,所以我决定开始编程。 为什么选择iOS和S ...
本文出自:,作者:Jameson Quave,译文出自:SwiftGG,译者:mmoaay 在Objective-C中我们经常会用到指针,有些方法也需要直接去操作指针,今天我们就来看看如何在Swift中使用指针。 在Swift中读C指针 下面这个Objective-C方法会返回一个int指针,或者说C术语里面的(int *):
@interface PointerB ...
本文出自:Natasha The Robot,作者:Natasha Murashev,译文出自:SwiftGG,译者:张伟璐 昨天,我在代码库中找到一段我所认为的极具Swift风格的代码。
var minionImages = [UIImage]() for i in 1...7 { if let minionImage = UIImage(named: &minionIcon-\(i) ...
本文出自:Swift and Painless,作者:Dominik Hauser,译文出自:SwiftGG,译者:宜东 正如大家所知,Swift中的结构体不遵守NSCoding协议。NSCoding只适用于继承自NSObject的类。可是结构体在Swift中的地位与使用频率都非常高,因此,我们需要一个能将结构体的实例归档和解档的方法。 Janie写过在Sonoplot工作时,他们团队对此的解决方法 ...
本文出自:owensd.io,译文出自:SwiftGG 最近Swift的热点都围绕在协议上,他们觉得任何东西都应该是协议。理论上这挺好,但是事实上,这种观点会产生一些副作用。 我在代码中使用协议时,总是牢记下面两条规则: 1.不要把协议当成类型 我看到的(和我一开始写的)许多方法都是在继承关系里把协议当成一个基类。我不认为这是协议的正确用法,这种设计模式仍然停留在“面向对象”的思维方式上。 换句话说 ...
在Xcode 6.3中,我们为Objective-C添加了新语言特性nullability注解。这个特性给Objective-C提供了表达API使用null和non-null统一的方式,相当于Swift语言中的Optional类型。Xcode 7继续为Objective-C与Swift之间更加自然的通信引入轻量级的泛型模型。泛型使得这两种语言能够可靠地融合并分享带有特定类型元素的集合。 这些特性对任 ...
本文出自:苹果官方Swift博客,译文出自:开发技术前线,译者:MrLoong Swift提供高性能、兼容Unicode的String作为标准库的一部分,在Swift 2.0中,String类型不再符合CollectionType协议,曾经String是字符的集合,类似于array。现在,String提供了一个公开字符集视图的charactes属性。 为什么会变?虽然模拟一个字符串作为字符集合看起来 ...
尽管在我之前的博文里我就写过关于管理状态的那些坑,但是有时候我们就是无法避免它们。其中一类管理状态的方式我们耳熟能详 - 单例。但是在Swift中有好几种不同的方式来实现一个单例。到底哪一个才是正确的方式呢?在这边博客里,我将和你好好聊聊单例的历史和在Swift中单例正确的实现方式。 如果你想直接就看在Swift中如何正确地写出单例同时看到证明其“正确性”,你可以直接滚动到这篇博文的底部。 让我们先 ...
& 上一页 1
相关知识库
4159关注/1293收录使用Swift开发SDK的优点是,生成的SDK对于Obj-C或是Swift调用都不需要自己去建桥接文件,因为Swift的SDK打包时默认已经自动生成供OC调用的.h文件。OC调用时直接import,sdk中的.h文件即可。而Swift调用时,import该SDK名即可。
制作SDK的整个过程也十分简单,网上的博客多的不能再多(大多基于OC)。
使用Swift开发,里面会遇到千奇百怪的坑!所以写这篇博客的目的分享下这些坑的解决经验。
1.工程组合的方式:
开发SDK,不建议直接把SDK当APP开发,不然每次SDK的导出非常麻烦。建议采用SDK工程和Demo工程组合的方式,这样利于导出也利于调试。
首先你新建一个framework的工程A开发SDK,再建立一个普通的APP工程B,然后把工程A拖到工程B中,这样就组成了一个工程。下次在开发的时候直接使用B工程开发即可。
这里需要注意的是,假如你需要在B中使用SDK,就需要把A产出的Product里的XXX.framework供B来引用,这里需要在B的demo工程中的Build Phases里设置2-3个地方去添加,比如
(1)Link Binary With Libraries
(2)embed frameworks
(3)copy bundle resources (假如该framework有图片,xib等资源,这里有个关于bundle的注意点下面等等会提到)
2.第三方的管理:
在开发SDK时,开发者应该有一个共识,那就是千万不能把三方的源码打包进自己的SDK。比如我需要用到MBProgressHUD,我把它封进SDK里,不但程序会很大,别人再次导入也会产生编译冲突。所以最好还是使用CocoaPods,在文档中告诉别人使用的三方库和版本号。
3.桥接文件:
假如我们在Swift的SDK中需要引用到OC文件,是不需要添加桥接文件的。(在普通app工程中是需要的)swift的SDK工程会自动生成一个xxxx.h的头文件,你需要做的有2步:
(1)在.h中import你使用到OC类的头文件。
(2)在SDK的工程设置中的Headers里,把.h放到public中,如下:
假如你之前的工程使用到了桥接文件,你要把它改成SDK,你需要把桥接文件干掉,然后把里面import的东西搬到xxxsdk.h中。
4.资源文件的调用:
假如你在SDK中使用到图片,Xib,Storyboard等资源,在APP中也许我们能直接调用,比如UIImage(Named:"xxx"),但是普通的APP会默认搜索工程目录,这也称为MainBundle。
但是SDK中,资源文件是以工程目录/xxxSDK.Framework/xxx.png的形式存放的,所以按直接名字取的方法,绝对是直接崩溃的。
这个坑我还没有找到完美的解决办法。
(1)最合理的方式,必然是把所有的资源文件,包括XIB、图片等全部加入一个Bundle,但是Bundle的位置也是在SDK中,同样尴尬的无法找到。解决办法是,在该资源的位置前面,加入xxxSDK.Framework/xxx.bundle找到这个Bundle,然后再去找到图片,但是Bundle这东西,太垃圾了,非常难用。
(2)一个比较简单,但不是很规范的方法,定义一个全局变量let SourceRootUrl = "xxxSDK.Framework/",然后在每次调用资源前面,加入这个目录关系,比如图片,UIImage(Named:SourceRootUrl+"xxx"),xib,storyboard同样需要。
关于这点,我觉得Xcode在之后应该会推出更好的解决办法。
5.CPU架构的支持:
这点非常坑,Xcode能debug出或者release出的架构非常单一,要么是真机架构的,要么是模拟器架构的,但实际上我们提供给开发者的SDK可能是真机和模拟器两个平台都需要的。
所以我们可以对两个库进行合并,使用lipo -create &a b -output c (具体方式自己百度搜索lipo -create),【这里要注意的是我们合并的是xxxSDK.Framework里的xxxSDK文件,而不是整个framework,合并成c后,我们再放入替换某个a或b】
但是这里有个坑,使用swift开发出的SDK,通过lipo -create合并出的Framework,OC是模拟器和真机都能调用的,但是Swift的工程缺只能调用其中1个,可能是和这种合并不是非常规范。
这一点,官方居然不提供点更直接点的方法?
然后就是,关于armv7s的架构(仅iPhone5),Xcode默认已经不支持,所以假如你其中一个第三方不支持armv7s,你的SDK也就不支持了,人家的APP也不可能支持了。
6.重名问题:
SDK的启动类和SDK名,不要命名成一样的。否则你会后悔的。
7.删除framework后残留问题
有时候也许你明明已经把SDK从工厂中挪走了,但是编译的时候还是不通过,甚至运行的时候出现未找到xxxSDK。
为什么?因为Xcode非常傻*。你把SDK挪走了,但是你之前加过target,link with libraries,bundle等还残留着之前那个目标framework,然后一运行,还是试图去加载之前那个framework,就崩溃了,真是傻啊。
8.莫名崩溃,又莫名好了
我感觉Xcode的隐形BUG已经非常的多了,尤其是结合Storyboard或是Xib后,BUG直接多一个数量级。
所以这也是很多人建议少用界面编辑器去做APP的原因,有时候就是莫名其妙的错。
然而你可能重启下电脑,关闭下Xcode,或许clean up一下,也许根本就没问题。
所以假如出现了一个长达几小时让人自信到不可能有问题的BUG,不妨重启clean up -& 重启Xcode -& 重启电脑下。
阅读(...) 评论()IOS开发之SWIFT进阶部分
时间: 17:36:55
&&&& 阅读:1239
&&&& 评论:
&&&& 收藏:0
标签:概述
上一篇文章《》 中对Swift的语法特点以及它和C、ObjC等其他语言的用法区别进行了介绍。当然,这只是Swift的入门基础,但是仅仅了解这些对于使用Swift 进行iOS开发还是不够的。在这篇文章中将继续介绍一些Swift开发中一些不常关注但是又必备的知识点,以便对Swift有进一步的了解。
和其他高级语言一样Swift中也增加了访问控制,在Swift中提供了private、internal、public三种访问级别,但是不同的 是Swift中的访问级别是基于模块(module,或者target)和源文件(.swift文件)的,而不是基于类型、命名空间声明。
private:只能访问当前源文件中的实体(注意Swift中的private和其他语言不太一样,它是基于源文件的,作用范围是整个源文件,如果一个源文件中有两个类,那么一个类可以访问另外一个类的私有成员)。
internal:可以访问当前模块中的其他任何实体,但是在模块外无法访问,这是所有实体的默认访问级别(通常在一个单目标Application中不需要自行设置访问级别)。
public:可以访问当前模块及其他模块中的任何实体(通常用于Framework)。
下面是关于Swift关于不同成员访问级别的约定规则:
如果一个类的访问级别是private那么该类的所有成员都是private(此时成员无法修改访问级别),如果一个类的访问级别是 internal或者public那么它的所有成员都是internal(如果类的访问级别是public,成员默认internal,此时可以单独修改 成员的访问级别),类成员的访问级别不能高于类的访问级别(注意:嵌套类型的访问级别也符合此条规则);
常量、变量、属性、下标脚本访问级别低于其所声明的类型级别,并且如果不是默认访问级别(internal)要明确声明访问级别(例如一个常量是一个private类型的类类型,那么此常量必须声明为private);
在不违反1、2两条规则的情况下,setter的访问级别可以低于getter的访问级别(例如一个属性访问级别是internal,那么可以添 加private(set)修饰将setter权限设置为private,在当前模块中只有此源文件可以访问,对外部是只读的);
必要构造方法(required修饰)的访问级别必须和类访问级别相同,结构体的默认逐一构造函数的访问级别不高于其成员的访问级别(例如一个成 员是private那么这个构造函数就是private,但是可以通过自定义来声明一个public的构造函数),其他方法(包括其他构造方法和普通方 法)的访问级别遵循规则1;
子类的访问级别不高于父类的访问级别,但是在遵循三种访问级别作用范围的前提下子类可以将父类低访问级别的成员重写成更高的访问级别(例如父类A 和子类B在同一个源文件,A的访问级别是public,B的访问级别是internal,其中A有一个private方法,那么A可以覆盖其 private方法并重写为internal);
协议中所有必须实现的成员的访问级别和协议本身的访问级别相同,其子协议的访问级别不高于父协议;
如果一个类继承于另一个类的同时实现了某个协议那么这个类的访问级别为父类和协议的最低访问级别,并且此类中方法访问级别和所实现的协议中的方法相同;
扩展的成员访问级别遵循规则1,但是对于类、结构体、枚举的扩展可以明确声明访问级别并且可以更低(例如对于internal的类,你可以声明一个private的扩展),而协议的访问级别不可以明确声明;
元组的访问级别是元组中各个元素的最低访问级别,注意:元组的访问级别是自动推导的,无法直接使用以上三个关键字修饰其访问级别;
函数的访问级是函数的参数、返回值的最低级别,并且如果其访问级别和默认访问级别(internal)不符需要明确声明;
枚举成员的访问级别等同于枚举的访问级别(无法单独设置),同时枚举的原始值、关联值的访问级别不能低于枚举的访问级别;
泛型类型或泛型函数的访问级别是泛型类型、泛型函数、泛型类型参数三者中最低的一个;
类型别名的访问级别不能高于原类型的访问级别;
&上面这些规则看上去比较繁琐,但其实很多内容理解起来也是顺理成章的(如果你是一个语言设计者相信大部分规则也会这么设计),下面通过一个例子对 于规则3做一解释,这一点和其他语言有所不同但是却更加实用。在使用ObjC开发时大家通常会有这样的经验:在一个类中希望某个属性对外界是只读的,但是 自己又需要在类中对属性进行写操作,此时只能直接访问属性对应的成员变量,而不能直接访问属性进行设置。但是Swift为了让语法尽可能精简,并没有成员 变量的概念,此时就可以通过访问控制来实现。
Person.swift
import Foundation
public class Person {
&&&&public private(set) var name:String
&&&&public init(name:String){
&&&&&&&&self.name = name
&&&&public func showMessage(){
&&&&&&&&println("name=\(name)")
main.swift
import Foundation
var p =& Person(name:"Kenshin")
println("name=\(p.name)")
p.showMessage()&
Xcode中的每个构建目标(Target)可以当做是一个模块(Module),这个构建目标可以是一个Application,也可以是一个通用的Framework(更多的时候是一个Application)。
Swift命名空间
熟悉ObjC的朋友都知道ObjC没有命名空间,为了避免类名重复苹果官方推荐使用类名前缀,这种做法从一定程度上避免了大部分问题,但是当你在项 目中引入一个第三方库而这个第三方库引用了一个和你当前项目中用到的同一个库时就会出现问题。因为静态库最终会编译到同一个域,最终导致编译出错。当然作 为一个现代化语言Swift一定会解决这个问题,可是如果查看Swift的官方文档,里面关于Swift的命名空间并没有太多详细的说明。但是Swift 的作者Chris Lattner在Twitter中回答了这个问题:
Namespacing is implicit in swift, all classes (etc) are implicitly scoped by the module (Xcode target) they are in. no class prefixes needed
Swift中是实现了命名空间功能的,只是这个命名空间不像C#的namespace或者Java中的package那样需要显式在文件中指定,而 是采用模块(Module)的概念:在同一个模块中所有的Swift类处于同一个命名空间,它们之间不需要导入就可以相互访问。很明显Swift的这种做 法是为了最大限度的简化Swift编程。其实一个module就可以看成是一个project中的一个target,在创建项目的时候默认就会创建一个 target,这个target的默认模块名称就是这个项目的名称(可以在target的Build Settings&Product Module Name配置)。
下面不妨看一个命名空间的例子,创建一个Single View Application应用&NameSpaceDemo&。默认情况下模块名称为&NameSpaceDemo&,这里修改为&Network&,并且 添加&HttpRequest.swift"。然后添加一个Cocoa Touch Framework类型的target并命名为&IO&,添加&File.swift&。然后在ViewController.swift中调用 HttpRequest发送请求,将请求结果利用File类来保存起来。
File.swift
import Foundation
public class File {
&&&&public var path:String!
&&&&public init(path:String) {
&&&&&&&&self.path = path
&&&&public func write(content:String){
&&&&&&&&var error:NSError?
&&&&&&&&content.writeToFile(path, atomically: true, encoding:NSUTF8StringEncoding, error: &error)
&&&&&&&&if error != nil {
&&&&&&&&&&&&println("write failure...")
&&&&public func read() -&String?{
&&&&&&&&var error:NSError?
&&&&&&&&var content = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: &error)
&&&&&&&&if error != nil {
&&&&&&&&&&&&println("write failure...")
&&&&&&&&return content
HttpRequest.swift
import Foundation
class HttpRequest {
&&&&class func request(urlStr:String,complete:(responseText:String?)-&()){
&&&&&&&&var url = NSURL(string: urlStr)
&&&&&&&&let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) -& Void in
&&&&&&&&&&&&var str:String?
&&&&&&&&&&&&if error == nil {
&&&&&&&&&&&&&&&&str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String
&&&&&&&&&&&&}
&&&&&&&&&&&&complete(responseText: str)
&&&&&&&&task.resume()
ViewController.swift
import UIKit
class ViewController: UIViewController {
&&&&let url = ""
&&&&let filePath = "/Users/KenshinCui/Desktop/file.txt"
&&&&override func viewDidLoad() {
&&&&&&&&super.viewDidLoad()
&&&&&&&&Network.HttpRequest.request(url, complete: { (responseText) -& () in
&&&&&&&&&&&&if let txt = responseText {
&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&var file = File(path: self.filePath)
&&&&&&&&&&&&&&&&file.write(txt)
&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&}else{
&&&&&&&&&&&&&&&&println("error...")
&&&&&&&&&&&&}
&&&&&&&&})
可以看到首先同一个Module中的HttpRequest类可以加上命名空间调用(当然这里可以省略),另外对于不同Modle下的File类通 过导入IO模块可以直接使用File类,但是这里需要注意访问控制,可以看到File类及其成员均声明为了public访问级别。 用模块进行命名空间划分的方式好处就是可以不用显式指定命名空间,然而这种方式无法在同一个模块中再进行划分,不过这个问题可以使用Swift中的嵌套类 型来解决。在下面的例子中仍然使用前面的两个类HttpRequest和File类来演示,不同的是两个类分别嵌套在两个结构体Network和IO之 中。
Network.HttpRequest.swift
import Foundation
struct Network {
&&&&class HttpRequest {
&&&&&&&&class func request(urlStr:String,complete:(responseText:String?)-&()){
&&&&&&&&&&&&var url = NSURL(string: urlStr)
&&&&&&&&&&&&let task = NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) -& Void in
&&&&&&&&&&&&&&&&var str:String?
&&&&&&&&&&&&&&&&if error == nil {
&&&&&&&&&&&&&&&&&&&&str = NSString(data: data, encoding: NSUTF8StringEncoding) as? String
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&complete(responseText: str)
&&&&&&&&&&&&}
&&&&&&&&&&&&task.resume()
IO.File.swift
import Foundation
struct IO {
&&&&class File {
&&&&&&&&var path:String!
&&&&&&&&init(path:String) {
&&&&&&&&&&&&self.path = path
&&&&&&&&func write(content:String){
&&&&&&&&&&&&var error:NSError?
&&&&&&&&&&&&content.writeToFile(path, atomically: true, encoding:NSUTF8StringEncoding, error: &error)
&&&&&&&&&&&&if error != nil {
&&&&&&&&&&&&&&&&println("write failure...")
&&&&&&&&&&&&}
&&&&&&&&func read() -&String?{
&&&&&&&&&&&&var error:NSError?
&&&&&&&&&&&&var content = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: &error)
&&&&&&&&&&&&if error != nil {
&&&&&&&&&&&&&&&&println("write failure...")
&&&&&&&&&&&&}
&&&&&&&&&&&&return content
main.swift
import Foundation
let url = ""
let filePath = "/Users/KenshinCui/Desktop/file.txt"
Network.HttpRequest.request(url, complete: { (responseText) -& () in
&&&&if let txt = responseText {
&&&&&&&&var file = IO.File(path: filePath)
&&&&&&&&file.write(txt)
&&&&}else{
&&&&&&&&println("error...")
Swift和ObjC互相调用
Swift的设计的初衷就是摆脱ObjC沉重的历史包袱,毕竟ObjC的历史太过悠久,相比于很多现代化语言它缺少一些很酷的语法特性,而且 ObjC的语法和其他语言相比差别很大。但是Apple同时也不能忽视ObjC的地位,毕竟ObjC经过二十多年的历史积累了大量的资源(开发者、框架、 类库等),因此在Swift推出的初期必须考虑兼容ObjC。但同时Swift和ObjC是基于两种不同的方式来实现的(例如ObjC可以在运行时决定对 象类型,但是Swift为了提高效率要求在编译时就必须确定对象类型),所以要无缝兼容需要做大量的工作。而作为开发人员我们有必要了解两种语言之间的转 化关系才能对Swift有更深刻的理解。
Swift和ObjC映射关系
其实从前面的例子中大家不难发现Swift和ObjC必然存在着一定的映射关系,例如对于文件的操作使用了字符串的writeToFile方法,在 网络请求时使用的NSURLSession,虽然调用方式不同但是其参数完全和做ObjC开发时调用方式一致。原因就是Swift编译器自动做了映射,下 面列举了部分Swift和ObjC的映射关系帮助大家理解:
SwiftObjC备注
Array、Dictionary、Set
NSArray、NSDictionary、NSSet
注意:ObjC中的数组和字典不能存储基本数据类型,只能存储对象类型,这样一来对于Swift中的Int、UInt、Float、Double、Bool转化时会自动桥接成NSNumber
NSInteger、NSUInteger
其他基本类型情况类似,不再一一列举
NSObjectProtocol
NSObject协议(注意不是NSObject类)
由于Swift在继承或者实现时没有类的命名空间的概念,而ObjC中既有NSObject类又有NSObject协议,所以在Swift中将NSObject协议对应成了NSObjectProtocol
CGContextRef
Core Foundation中其他情况均是如此,由于Swift本身就是引用类型,在Swift不需要再加上&Ref&
@selector(ab:)
Swift可以自动将字符串转化成成selector
@NSCopying
init(x:X,y:Y)
initWithX:(X)x y:(Y)y
构造方法映射,Swift会去掉&With&并且第一个字母小写作为其第一个参数,同时也不需要调用alloc方法,但是需要注意ObjC中的便利工厂方法(构建对象的静态方法)对应成了Swift的便利构造方法
func xY(a:A,b:B)
void xY:(A)a b:(B)b
extension(扩展)
category(分类)
注意:不能为ObjC中存在的方法进行extension
Closure(闭包)
block(块)
注意:Swift中的闭包可以直接修改外部变量,但是block中要修改外部变量必须声明为__block
Swift兼容大部分ObjC(通过类似上面的对应关系),多数ObjC的功能在Swift中都能使用。当然,还是有个别地方Swift并没有考虑 兼容ObjC,例如:Swift中无法使用预处理指令(例如:宏定义,事实上在Swift中推举使用常量定义);Swift中也无法使用 performSelector来执行一个方法,因为Swift认为这么做是不安全的。
相反,如果在ObjC中使用Swift也同样是可行的(除了个别Swift新增的高级功能)。Swift中如果一个类继承于NSObject,那么 他会自动和ObjC兼容,这样ObjC就可以按照上面的对应关系调用Swift的方法、属性等。但是如果Swift中的类没有继承于NSObject呢? 此时就需要使用一个关键字&@objc&进行标注,ObjC就可以像使用正常的ObjC编码一样调用Swift了(事实上继承于NSObject的类之所 以在ObjC中能够直接调用也是因为编译器会自动给类和非private成员添加上@objc,类似的@IBoutlet、@IBAction、 @NSManaged修饰的方法属性Swift编译器也会自动添加@objc标记)。
Swift调用ObjC&
当前ObjC已经积累了大量的第三方库,相信在Swift发展的前期调用已经存在的ObjC是比较常见的。在Swift和ObjC的兼容性允许你在 一个项目中使用两种语言混合编程(称为&mix and match&),而不管这个项目原本是基于Swift的还是ObjC的。无论是Swift中调用ObjC还是ObjC中调用Swift都是通过头文件暴漏 对应接口的,下图说明了这种交互方式:
不难发现,要在Swift中调用ObjC必须借助于一个桥接头文件,在这个头文件中将ObjC接口暴漏给Swift。例如你可以创建一个 &xx.h&头文件,然后使用&#import&导入需要在Swift中使用的ObjC类,同时在Build Settings的&Objective-C Bridging Header&中配置桥接文件&xx.h&。但是好在这个过程Xcode可以帮助你完成,你只需要在Swift项目中添加ObjC文件,Xcode就会询 问你是否创建桥接文件,你只需要点击&Yes&就可以帮你完成上面的操作:
为了演示Swift中调用ObjC的简洁性, 下面创建一个基于Swift的Single View Application类型的项目,现在有一个基于ObjC的&KCLoadingView&类,它可以在网络忙时显示一个加载动画。整个类的实现很简 单,就是通过一个基础动画实现一个图片的旋转。
KCLoadingView.h
#import &UIKit/UIKit.h&
@interface KCLoadingView : UIImageView
- (void)start;
- (void)stop;
KCLoadingView.m
#import "KCLoadingView.h"
static NSString *const kAnimationKey = @"rotationAnimation";
@interface KCLoadingView ()
@property(strong, nonatomic) CABasicAnimation *rotationA
@implementation KCLoadingView
#pragma mark - 生命周期及其基类方法
- (instancetype)initWithFrame:(CGRect)frame {
&&&&if (self = [super initWithFrame:frame]) {
&&&&&&&&[self setup];
&&&&return self;
#pragma mark - 公共方法
- (void)start {
&&&&[self.layer addAnimation:self.rotationAnimation forKey:kAnimationKey];
- (void)stop {
&&&&[self.layer removeAnimationForKey:kAnimationKey];
#pragma mark - 私有方法
- (void)setup {
&&&&self.image = [UIImage imageNamed:@"loading"];
&&&&CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
&&&&rotationAnimation.toValue = [NSNumber numberWithFloat:M_PI * 2.0];
&&&&rotationAnimation.duration = 0.7;
&&&&rotationAnimation.cumulative = YES;
&&&&rotationAnimation.repeatCount = HUGE_VALF;
&&&&self.rotationAnimation = rotationA
&&&&[self.layer addAnimation:rotationAnimation forKey:kAnimationKey];
当将这个类加入到项目时就会提示你是否创建一个桥接文件,在这个文件中导入上面的&KCLoadingView&类。现在这个文件只有一行代码
ObjCBridge-Bridging-Header.h
#import "KCLoadingView.h"&
接下来就可以调用这个类完成一个加载动画,调用关系完全顺其自然,开发者根本感觉不到这是在调用一个ObjC类。
ViewController.swfit
import UIKit
class ViewController: UIViewController {
&&&&lazy var loadingView:KCLoadingView = {
&&&&&&&&var size=UIScreen.mainScreen().bounds.size
&&&&&&&&var lv = KCLoadingView()
&&&&&&&&lv.frame.size=CGSizeMake(37.0, 37.0)
&&&&&&&&lv.center=CGPointMake(size.width*0.5, size.height*0.5)
&&&&&&&&return lv
&&&&lazy private var converView:UIView = {
&&&&&&&&var cv = UIView(frame: UIScreen.mainScreen().bounds)
&&&&&&&&cv.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5)
&&&&&&&&return cv
&&&&override func loadView() {
&&&&&&&&var image = UIImage(named: "iOS9")
&&&&&&&&var background = UIImageView(frame: UIScreen.mainScreen().bounds)
&&&&&&&&background.userInteractionEnabled=true
&&&&&&&&background.image=image
&&&&&&&&self.view = background
&&&&override func viewDidLoad() {
&&&&&&&&super.viewDidLoad()
&&&&&&&&self.view.addSubview(self.converView)
&&&&&&&&self.view.addSubview(self.loadingView)
&&&&&&&&loadingView.start()
&&&&override func touchesBegan(touches: Set, withEvent event: UIEvent) {
&&&&&&&&loadingView.stop()
ObjC调用Swift
从前面的Swift和ObjC之间的交互图示可以看到ObjC调用Swift是通过Swift生成的一个头文件实现的,好在这个头文件是由编译器自 动完成的,开发者不需要关注,只需要记得他的格式即可&项目名称-Swift.h&。如果在ObjC项目中使用了Swift,只要在ObjC的&.m&文 件中导入这个头文件就可以直接调用Swift,注意这个生成的文件并不在项目中,它在项目构建的一个文件夹中(可以按住Command点击头文件查看)。 同样通过前面的例子演示如何在ObjC中调用Swift,新建一个基于ObjC的项目(项目名称&UseSwiftInObjC&),并且这次加载动画控 件使用Swift编写。
LoadingView.swift
import UIKit
public class LoadingView:UIImageView {
&&&&let basicAnimationKey = "rotationAnimation"
&&&&lazy var rotationAnimation:CABasicAnimation = {
&&&&&&&&var animation = CABasicAnimation(keyPath: "transform.rotation.z")
&&&&&&&&animation.toValue = 2*M_PI
&&&&&&&&animation.duration = 0.7
&&&&&&&&animation.cumulative = true
&&&&&&&&animation.repeatCount = .infinity
&&&&&&&&return animation
&&&&convenience init(){
&&&&&&&&self.init(frame: CGRectZero)
&&&&override init(frame: CGRect) {
&&&&&&&&super.init(frame: frame)
&&&&&&&&self.image = UIImage(named: "loading")
&&&&required public init(coder aDecoder: NSCoder) {
&&&&&&&&super.init(coder: aDecoder)
&&&&&&&&self.image = UIImage(named: "loading")
&&&&public func start() {
&&&&&&&&self.layer.addAnimation(self.rotationAnimation, forKey: basicAnimationKey)
&&&&public func stop() {
&&&&&&&&self.layer.removeAnimationForKey(basicAnimationKey)
&然后可以直接在ObjC代码中导入自动生成的文件&UseSwiftInObjC-Swift.h&并调用。
ViewController.m
#import "ViewController.h"
#import "UseSwiftInObjC-Swift.h"
@interface ViewController ()
@property (strong,nonatomic) UIView *converV
@property (strong,nonatomic) LoadingView *loadingV
@implementation ViewController
-(void)loadView{
&&&&UIImage *image = [UIImage imageNamed:@"iOS9"];
&&&&UIImageView *background = [[UIImageView alloc]initWithImage:image];
&&&&background.userInteractionEnabled = YES;
&&&&self.view =
- (void)viewDidLoad {
&&&&[super viewDidLoad];
&&&&[self.view addSubview:self.converView];
&&&&[self.view addSubview:self.loadingView];
&&&&[self.loadingView start];
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
&&&&[self.loadingView stop];
#pragma mark - 属性
-(UIView *)converView{
&&&&if (!_converView) {
&&&&&&&&_converView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
&&&&&&&&_converView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5];
&&&&return _converV
-(LoadingView *)loadingView{
&&&&if(!_loadingView){
&&&&&&&&CGSize screenSize = [UIScreen mainScreen].bounds.
&&&&&&&&CGFloat loadingViewWidth = 37.0;
&&&&&&&&_loadingView=[[LoadingView alloc]init];
&&&&&&&&_loadingView.frame=CGRectMake((screenSize.width-loadingViewWidth)*0.5, (screenSize.height - loadingViewWidth)*0.5, loadingViewWidth, loadingViewWidth);
&&&&return _loadingV
虽然生成的头文件并不会直接放到项目中,但是可以直接按着Command键查看生成的文件内容,当然这个文件比较长,里面使用了很多宏定义判断,这里只关心最主要部分。
UseSwiftInObjC-Swift.h
SWIFT_CLASS("_TtC14UseSwiftInObjC11LoadingView")
@interface LoadingView : UIImageView
- (SWIFT_NULLABILITY(nonnull) instancetype)initWithCoder:(NSCoder * __nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER;
可以清晰的看到Swift确实进行了桥接,通过头文件将接口暴漏给了ObjC。但是注意前面说过的访问控制,如果类和方法在Swift中不声明为 public,那么在ViewController.m中是无法调用的。事实上,如果方法不是public在UseSwiftInObjC- Swift.h中根本不会生成对应的方法声明。
扩展&Swift调用C
由于ObjC是C的超集,使得在ObjC可以无缝访问C语言。但是Swift的产生就是ObjC without C,因此在Swift中不可能像在ObjC中混编入C一样简单。但是考虑到C语言的强大以及历时那么多年留下了丰富的类库,有时候又不得不使用 它,Swift中还是保留了与一定数量的C语言类型和特性的兼容。前面介绍过关于如何在Swift中使用ObjC的知识,事实上在Swift中使用C也是 类似的(因为ObjC是C的超集,ObjC既然可以桥接,C自然也可以),你需要一个桥接文件,不同的是ObjC中的很多内容在桥接到Swift时都是类 似,很容易上手。例如ObjC中使用的NSObject,在Swift中仍然对应NSObject,很多时候开发人员感觉不到这种转化,只是编程语言发生 了变化。但是C导入Swift就需要必须要了解具体的对应关系:
C类型Swift类型说明
char,signed char
类似的unsigned char对应CUnsignedChar
类似的unsigned int对应CUnsignedInt
类似的unsigned short对应CUnsignedShort
类似的unsigned long对应CUnsignedLong
类似的unsigned long long 对应 CUnsignedLongLong
枚举typedef NS_ENUM(NSInteger,A){AB,AC}
enum A:Int{case B,C}
去掉对应的前缀 ,注意C中的NS_Options会对应成Swift中实现OptionSetType的结构体
对应Swift中的结构体&
Swift中不能完全支持联合,建议使用枚举关联值代替
UnsafeMutablePointer&Type&
作为返回类型、变量、参数类型时
const Type *
UnsafePointer&Type&
作为返回类型、变量、参数类型时
Type *const *
UnsafePointer&Type&
对于类类型
Type *__strong *
UnsafeMutablePointer&Type&
对于类类型
AutoreleasingUnsafePointer&Type&
对于类类型
&对于其他类型的映射关系都很容易理解,这里主要说一下指针的内容。通过上表可以看到在C中定义的一些指针类型当在Swift中使用时会有对应的类 型,但是如果一个参数为某种指针类型,实际调用时应该使用何种Swift数据类型的数据作为参数调用呢?例如参数为 UnsafePointer&Type&,是否只能传入UnsafePointer&Type&呢,其实也可以传入nil,并且 最终调用时将会转化为null指针来调用。下表列出了这种参数调用对应关系:
可用类型最终转化类型
&UnsafePointer&Type&、UnsafeMutablePointer&Type&、AutoreleasingUnsafeMutablePointer&Type&
&UnsafePointer&Type&
&如果Type为Int、或者Int8将最终转化为UTF8字符串
&&typeValue
&Type类型的数组([typeValue1,typeValue2])
&数组首地址
&UnsafeMutablePointer&Type&
&UnsafeMutablePointer&Type&&
&&typeValue
&Type类型的数组的地址(&[typeValue1,typeValue2])
&AutoreleasingUnsafeMutablePointer&Type&
&AutoreleasingUnsafeMutablePointer&Type&
&&typeValue
下面不妨看一下如何在Swift中使用C语言,假设现在有一个用于字符串拼接的C库函数&stringAppend(char*,const char *)&,将其对应的文件导入到一个Swift项目中按照提示添加桥接头文件并在桥接头文件中引入对应的C文件。
#ifndef __UseCInSwift__Common__
#define __UseCInSwift__Common__void stringAppend(char *source, char *toAppend)
void stringAppend(char *source,const char *toAppend);
#include "string.h"
void stringAppend(char *source,const char *toAppend) {
&&&&unsigned long sourceLen = strlen(source);
&&&&char *pSource = source + sourceL
&&&&const char *pAppend = toA
&&&&while (*pAppend != ‘\0‘) {
&&&&&&&&*pSource++ = *pAppend++;
UseCInSwift-Bridging-Header.h
#import "string.h"
然后在Swift中调用上面的C函数
import Foundation
var sourceStr:String = "Hello"
var appendStr:String = ",World!"
var sourceCStr = (sourceStr as NSString).UTF8String
var sourceMutablePointer:UnsafeMutablePointer = UnsafeMutablePointer(sourceCStr)
stringAppend(sourceMutablePointer,appendStr)
println(String.fromCString(sourceMutablePointer)!)
&可以看到&char *&参数转化成了Swift中的UnsafeMutablePointer&Int8&,而将&const char *&转化成了UnsafePointer&Int8&。根据上面表格中的调用关系,如果参数为 UnsafeMutablePointer&Type&可以传入nil、UnsafeMutablePointer&Type& 或者元素地址,很明显这里需要使用UnsafeMutablePointer&Int8&;而如果参数为 UnsafePointer&Type&并且Type为Int8或者Int则可以直接传入String类型的参数,因此也就有了上面的调用关 系。
当然,上面这种方式适合所有在Swift中引入C语言的情况,但是为了方便调用,在Swift中默认已经module了常用的C语言类库 Darwin,这个类库就作为了标准的Swift类库不需要再进行桥接,可以直接导入模块(例如import Darwin,但是事实上Foundation模块已经默认导入了Darwin,而UIKit又导入了Foundation模块,因此通常不需要手动导入 Darwin)。那么对于没有模块化的C语言类库(包括第三方类库和自己定义的C语言文件等)能不能不使用桥接文件呢?答案就是使用隐藏符号 &@asmname&,通过@asmname可以将C语言的函数不经过桥接文件直接映射为Swift函数。例如可以移除上面的桥接头文件,修改 main.swift函数,通过@asmname加stringAppend映射成为Swift函数(注意重新映射的Swift函数名称不一定和C语言函 数相同):
&main.swift
import Foundation
@asmname("stringAppend") func stringAppend(var sourceStr:UnsafeMutablePointer,var apendStr:UnsafePointer ) -& Void
var sourceStr:String = "Hello"
var appendStr:String = ",World!"
var sourceCStr = (sourceStr as NSString).UTF8String
var sourceMutablePointer:UnsafeMutablePointer = UnsafeMutablePointer(sourceCStr)
stringAppend(sourceMutablePointer,appendStr)
println(String.fromCString(sourceMutablePointer)!)
更多Swift标准类库信息可以查看:/andelf/Defines-Swift&
熟悉C#、Java的朋友不难理解反射的概念,所谓反射就是可以动态获取类型、成员信息,在运行时可以调用方法、属性等行为的特性。 在使用ObjC开发时很少强调其反射概念,因为ObjC的Runtime要比其他语言中的反射强大的多。在ObjC中可以很简单的实现字符串和类型的转换 (NSClassFromString()),实现动态方法调用(performSelector: withObject:),动态赋值(KVC)等等,这些功能大家已经习以为常,但是在其他语言中要实现这些功能却要跨过较高的门槛,而且有些根本就是无 法实现的。不过在Swift中并不提倡使用Runtime,而是像其他语言一样使用反射(Reflect),即使目前Swift中的反射还没有其他语言中 的反射功能强大(Swift还在发展当中,相信后续版本会加入更加强大的反射功能)。
在Swift中反射信息通过MirrorType协议来描述,而Swift中所有的类型都能通过reflect函数取得MirrorType信息。先看一下MirrorType协议的定义(为了方便大家理解,添加了相关注释说明):
protocol MirrorType {
&&&&var value: Any { get }
&&&&var valueType: Any.Type { get }
&&&&var objectIdentifier: ObjectIdentifier? { get }
&&&&var count: Int { get }
&&&&subscript (i: Int) -& (String, MirrorType) { get }
&&&&var summary: String { get }
&&&&var quickLookObject: QuickLookObject? { get }
&&&&var disposition: MirrorDisposition { get }
获取到一个变量(或常量)的MirrorType之后就可以访问其类型、值、类型种类等元数据信息。在下面的示例中将编写一个函数简单实现一个类似于ObjC中&valueForKey:&的函数。
import UIKit
struct Person {
&&&&var name:String
&&&&var age:Int = 0
&&&&func showMessage(){
&&&&&&&&print("name=\(name),age=\(age)")
func valueForKey(key:String,obj:Any) -& Any?{
&&&&var objInfo:MirrorType = reflect(obj)
&&&&for index in 0..&objInfo.count {
&&&&&&&&let (name,mirror) = objInfo[index]
&&&&&&&&if name == key {
&&&&&&&&&&&&return mirror.value
&&&&return nil;
var p = Person(name: "Kenshin", age: 29)
var name = valueForKey("name", p)
print("p.name=\(name)")
可以看到,通过反射可以获取到变量(或常量)的信息,并且能够读取其成员的值,但是Swift目前原生并不支持给某个成员动态设置值 (MirrorType的value属性是只读的)。如果想要进行动态设置,可以利用前面介绍的Swift和ObjC兼容的知识来实现,Swift目前已 经导入了Foundation,只要这个类是继承于NSObject就会有对应的setValue:forKey:方法来使用KVC。当然,这仅限于类, 对应结构体无能为力。
和KVC一样,在Swift中使用KVO也仅限于NSObject及其子类,因为KVO本身就是基于KVC进行动态派发的,这些都属于运行时的范 畴。Swift要实现这些动态特性需要在类型或者成员前面加上@objc(继承于NSObject的子类及非私有成员会自动添加),但并不是说加了 @objc就可以动态派发,因为Swift为了性能考虑会优化为静态调用。如果确实需要使用这些特性Swift提供了dynamic关键字来修饰,例如这 里要想使用KVO除了继承于NSObject之外就必须给监控的属性加上dynamic关键字修饰。下面的演示中说明了这一点:
import Foundation
class Acount:NSObject {
&&&&dynamic var balance:Double = 0.0
class Person:NSObject {
&&&&var name:String
&&&&var account:Acount?{
&&&&&&&&didSet{
&&&&&&&&&&&&if account != nil {
&&&&&&&&&&&&&&&&account!.addObserver(self, forKeyPath: "balance", options: .Old, context: nil);
&&&&&&&&&&&&}
&&&&init(name:String){
&&&&&&&&self.name = name
&&&&&&&&super.init()
&&&&override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer) {
&&&&&&&&if keyPath == "balance" {
&&&&&&&&&&&&var oldValue = change[NSKeyValueChangeOldKey] as! Double
&&&&&&&&&&&&var newValue = (account?.balance)!
&&&&&&&&&&&&print("oldValue=\(oldValue),newValue=\(newValue)")
var p = Person(name: "Kenshin Cui")
var account = Acount()
account.balance =
p.account = account
p.account!.balance =
注意:对于系统类(或一些第三方框架)由于无法修改其源代码如果要进行KVO监听,可以先继承此类然后进行使用dynamic重写;此外,并非只有 KVO需要加上dynamic关键字,对于很多动态特性都是如此,例如要在Swift中实现Swizzle方法替换,方法前仍然要加上dynamic,因 为方法的替换也需要动态派发。
Swift使用ARC来自动管理内存,大多数情况下开发人员不需要手动管理内存,但在使用ObjC开发时,大家都会遇到循环引用的问题,在 Swift中也不可避免。 举例来说,人员有一个身份证(Person有idCard属性),而身份证就有一个拥有者(IDCard有owner属性),那么对于一个Person对 象一旦建立了这种关系之后就会和IDCard对象相互引用而无法被正确的释放。
例如下面的代码在执行完test之后p和idCard两个对象均不会被释放:
import Foundation
class Person {
&&&&var name:String
&&&&var idCard:IDCard
&&&&init(name:String,idCard:IDCard){
&&&&&&&&self.name = name
&&&&&&&&self.idCard = idCard
&&&&&&&&idCard.owner = self
&&&&deinit{
&&&&&&&&println("Person deinit...")
class IDCard {
&&&&var no:String
&&&&var owner:Person?
&&&&init(no:String){
&&&&&&&&self.no = no
&&&&deinit{
&&&&&&&&println("IDCard deinit...")
func test(){
&&&&var idCard = IDCard(no:"888888")
&&&&var p = Person(name: "Kenshin Cui",idCard:idCard)
println("wait...")
两个对象之间的引用关系如下图:
为了避免这个问题Swift采用了和ObjC中同样的概念:弱引用,通常将被动的一方的引用设置为弱引用来解决循环引用问题。例如这里可以将 IDCard中的owner设置为弱引用。因为IDCard对于Person的引用变成了弱引用,而Person持有IDCard的强引用,这样一来 Person作为主动方,只要它被释放后IDCard也会跟着释放。如要声明弱引用可以使用weak和unowned关键字,前者用于可选类型后者用于非 可选类型,相当于ObjC中的__weak和__unsafe_unretained(因为weak声明的对象释放后会设置为nil,因此它用来修饰可选 类型)。
import Foundation
class Person {
&&&&var name:String
&&&&var idCard:IDCard
&&&&init(name:String,idCard:IDCard){
&&&&&&&&self.name = name
&&&&&&&&self.idCard = idCard
&&&&&&&&idCard.owner = self
&&&&deinit{
&&&&&&&&println("Person deinit...")
class IDCard {
&&&&var no:String
&&&&weak var owner:Person?
&&&&init(no:String){
&&&&&&&&self.no = no
&&&&deinit{
&&&&&&&&println("IDCard deinit...")
func test(){
&&&&var idCard = IDCard(no:"888888")
&&&&var p = Person(name: "Kenshin Cui",idCard:idCard)
println("wait...")
现在两个对象之间的引用关系如下图:
当然类似于上面的引用关系实际遇到的并不多,更多的还是存在于闭包之中(ObjC中多出现于Block中),因为闭包会持有其内部引用的元素。下面 简单修改一下上面的例子,给Person添加一个闭包属性,并且在其中访问self,这样闭包自身就和Person类之间形成循环引用。
import Foundation
class Person {
&&&&let name:String
&&&&lazy var description:()-&NSString = {
&&&&&&&&return "name = \(self.name)"
&&&&init(name:String){
&&&&&&&&self.name = name
&&&&deinit{
&&&&&&&&println("Person deinit...")
func test(){
&&&&var p = Person(name: "Kenshin Cui")
&&&&println(p.description())
println("wait...")
Swift中使用闭包捕获列表来解决闭包中的循环引用问题,这种方式有点类似于ObjC中的weakSelf方式,当时语法更加优雅, 具体实现如下:
import Foundation
class Person {
&&&&let name:String
&&&&lazy var description:()-&NSString = {
&&&&&&&&[unowned self] in
&&&&&&&&return "name = \(self.name)"
&&&&init(name:String){
&&&&&&&&self.name = name
&&&&deinit{
&&&&&&&&println("Person deinit...")
func test(){
&&&&var p = Person(name: "Kenshin Cui")
&&&&println(p.description())
println("wait...")
指针与内存
除了循环引用问题,Swift之所以将指针类型标识为&unsafe&是因为指针没办法像其他类型一样进行自动内存管理,因此有必要了解一下指针和 内存的关系。在Swift中初始化一个指针必须通过alloc和initialize两步,而回收一个指针需要调用destroy和dealloc(通常 dealloc之后还会将指针设置为nil)。
import Foundation
class Person {
&&&&var name:String
&&&&init(name:String){
&&&&&&&&self.name = name
&&&&deinit{
&&&&&&&&println("Person\(name) deinit...")
func test(){
&&&&var p = Person(name: "Kenshin Cui")
&&&&var pointer:UnsafeMutablePointer = UnsafeMutablePointer.alloc(1)
&&&&pointer.initialize(p)
&&&&var p2 = pointer.memory
&&&&println(p===p2)
&&&&p2.name = "Kaoru"
&&&&println(p.name)
&&&&pointer.destroy()
&&&&pointer.dealloc(1)
&&&&pointer = nil
println("waiting...")
运行程序可以看到p对象在函数执行结束之后被销毁,但是如果仅仅将pointer设置为nil是无法销毁Person对象的,这很类似于之前的 MRC内存管理,在Swift中使用指针需要注意:谁创建(alloc,malloc,calloc)谁释放。 当然上面演示中显然对于指针的操作略显麻烦,如果需要对一个变量进行指针操作可以借助于Swift中提供的一个方法withUnsafePointer。 例如想要利用指针修改Person的name就可以采用下面的方式:
var p = Person(name: "Kenshin Cui")
var p2 = withUnsafeMutablePointer(&p, {
&&&&(pointer:UnsafeMutablePointer) -& Person in
&&&&pointer.memory.name = "Kaoru"
&&&&return pointer.memory
println(p.name)
在前面的C语言系列文章中有一部分内容用于介绍如何利用指针遍历一个数组,当然在Swift中仍然可以采用这种方式,但是在Swift中如果想要使 用指针操作数组中每个元素的话通常借助于另一个类型UnsafeMutableBufferPointer。这个类表示一段连续内存,通常用于表示数组或 字典的指针类型。
import Foundation
var array:[String] = ["Kenshin","Kaorsu","Tom"]
var pointer = UnsafeMutableBufferPointer(start: &array, count: 3)
var baseAddress = pointer.baseAddress as UnsafeMutablePointer
println(baseAddress.memory)
for index in 1...pointer.count {
&&&&println(baseAddress.memory)
&&&&baseAddress = baseAddress.successor()
&扩展&Core Foundation
Core Foundation作为iOS开发中最重要的框架之一,在iOS开发中有着重要的地位,但是它是一组C语言接口,在使用时需要开发人员自己管理内存。在 Swift中使用Core Foundation框架(包括其他Core开头的框架)需要区分这个API返回的对象是否进行了标注:
1.如果已经标注则在使用时完全不用考虑内存管理(它可以自动管理内存)。
2.如果没有标注则编译器不会进行内存管理托管,此时需要将这个非托管对象转化为托管对象(当然你也可以使用retain()、release() 或者autorelease()手动管理内存,但是不推荐这么做)。当然,苹果开发工具组会尽可能的标注这些API以实现C代码和Swift的自动桥接, 但是在此之前未标注的API会返回Unmanaged&Type&结构,可以调用takeUnretainedValue()和 takeRetainedValue()方法将其转化为可以自动进行内存管理的托管对象(具体是调用前者还是后者,需要根据是否需要开发者自己进行内存管 理而定,其本质是使用takeRetainedValue()方法,在对象使用完之后会调用一次release()方法。按照Core Foundation的命名标准,通常如果函数名中含&Create&、&Copy&、&Retain&关键字需要调用 takeRetainedValue()方法来转化成托管对象)。
当然,上述两种方式均是针对系统框架而言,如果是开发者编写的类或者第三方类库,应该尽可能按照Cocoa规范命名并且在合适的地方使用CF_RETURNS_RETAINED和CF_RETURNS_NOT_RETAINED来进行标注以便可以进行自动内存管理。
本文来源:/kenshincui/p/4824810.html标签:
&&国之画&&&& &&&&chrome插件&&
版权所有 京ICP备号-2
迷上了代码!

我要回帖

更多关于 react native是前端吗 的文章

 

随机推荐