使用swift 中的注意,不断完善中
首先,隆重推荐文章http://www.infoq.com/cn/articles/swift-brain-gym-optional swift 烧脑体操!目前有4篇文章,说的都很好!
1. 应该充分利用swfit的新特性
比如如果按照oc里的习惯,调用一个delegate中都optional函数应该这样写
if delegate != nil && delegate!.respondsToSelector("downloadProgress:progress:"){
delegate!.downloadProgress!(self, progress: totalProgress)
}
先检查是不是nil,再检查是否实现了方法,而swift应该这样写
delegate?.downloadProgress?(self, progress: totalProgress)
简单了许多!
2. Optional 和 as? as!
class Foo{
}
class SubFoo:Foo{
}
let foo:SubFoo? = SubFoo()
if let realfoo = foo as! SubFoo? { //
print(realfoo)
} if let realfoo = foo as? SubFoo? { //
print(realfoo)
} if let realfoo = foo as! SubFoo! { //
print(realfoo)
} //if let realfoo = foo as! SubFoo { //4
// print(realfoo)
//} if let realfoo = foo as? SubFoo { //
print(realfoo)
}
if let realfoo = foo as? SubFoo { //6
print(realfoo)
}
下面是具体输出
SubFoo
Optional(SubFoo)
SubFoo
SubFoo SubFoo
这里,第四个是错误的写法,如果打开,会提示错误
Initializer for conditional binding must have Optional type, not 'SubFoo'
就是说,foo as! SubFoo 返回的不是optional,就是SubFoo类型。
在对比上面的例子,就可以总结出,foo as! SubFoo 返回的就是 !号后面的类型的数据;而foo as? SubFoo? 返回的是 ?号后面类型的optional类型,这里可以看第二条,返回的是SubFoo?的optional型,解包后,得到了SubFoo?类型。
说到这里,我们再看看optional类型,
public enum Optional<Wrapped> : ExpressibleByNilLiteral
其实,它是一个enum。 说到enum,在c语言里就有,但是在c语言中,它仅仅是int型的另一种写法,方便编码人员明白其代表的意义。但是在swift中,enum得到了极大的拓展。
为什么要使用enum类型?就是其中的每个case类型,具有某种抽象上的关联,讲他们统一放在一个enum中,可以让定义的变量从这些case类型中选出需要的一个,方便编程。
首先,enum 可以指定raw属性对应的存储类型,比如:
enum Suit:Int {
case spades, hearts, diamonds, clubs
}
Suit.clubs.rawValue的值就是3,注意Suit.clubs可不是3. Suit.spades, Suit.hearts,Suit.clubs,Suit.diamonds它们都是 Suit类型。如果不使用rawValue属性,它们就一个enum对象,不是整形,也不是字符串。当使用print输出这个对象时,系统会自动把这个对象转化为字符串对象,系统提供了默认的enum类型对象转化为string方法,就是case后面定义的名字。比如Suit.clubs在print中的输出就是clubs。如果你不喜欢这种输出,可以让定义的enum类型实现CustomStringConvertible协议,自定义转化为string时的输出。
如果不指定raw的属性,却对case赋值,就会有如下错误:
再如:
enum Suit:String {
case spades, hearts, diamonds, clubs }
Suit.clubs.rawValue的值就是 clubs。
当不指定统一的raw类型时,可以在case中分开指定。
比如下例:
enum ServerResponse{
case result(String, String)
case failure(String)
case testCase(AnyObject)
}
let test = ServerResponse.testCase(NSObject())
switch test {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
print("Failure... \(message)")
case let .testCase(obj):
print("test \(obj)")
}
从这个例子,我们可以看出,其实swift的enum,就如同在每个case里多定义了一个叫做raw指针,可以指向具体对象,极大地拓展了c语言中的enum。所以即使同属于一个enum,raw所指向的类型也会大有不同!
附上一个自定义输出内容的代码:
enum Rank: Int, CustomStringConvertible { //这里看出 可以使用一个类型--代表rawValue的类型,多个协议--代表这个enum的特性,去定义enum
case ace =
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king var description: String {
switch self {
case .ace:
return "A"
case .jack:
return "J"
case .queen:
return "Q"
case .king:
return "K"
default:
return String(self.rawValue)
}
}
}
看过了enum,我们再回头看看optional的部分定义:
public enum Optional<Wrapped> : ExpressibleByNilLiteral { /// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none /// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
}
/// A type that can be initialized using the nil literal, `nil`.
///
/// `nil` has a specific meaning in Swift---the absence of a value. Only the
/// `Optional` type conforms to `ExpressibleByNilLiteral`.
/// `ExpressibleByNilLiteral` conformance for types that use `nil` for other
/// purposes is discouraged.
///
/// - SeeAlso: `Optional`
public protocol ExpressibleByNilLiteral { /// Creates an instance initialized with `nil`.
public init(nilLiteral: ())
}
我截取了定义的一部分。可以看出这里使用了模板,有2个case,其中some的rawValue是一个Wrapped(模板)类型指针,指向具体的数据。none这个case,就代表了空对象,也就是我们在其他语言里常用到的null。在swift的代码里,常用nil代替Optional<Wrapped>.none这种复杂的写法,但是我们可以看出,Optional.none才真正是swift中的空类型。
说到这里,再谈一下在optional里常用到的符号 !
这个叹号和optional类型连用时有2种情况:
第一种:出现在类型声明中,举一个特殊的例子:
class Person{
public init!()
}
这个初始化函数的返回值就是用 ! 号标识的。它表示,返回值是一个optional类型,并且,在访问这个变量时,会自动进行解包,访问对应的raw值.
let person1 = Person()这里的 person1就是 optional类型。
另外,变量的赋值,无法触发自动解包操作,变量仍然会取optional类型,比如
let person2 = person1 ,这里的person2 也是optional类型。
第二种,进行具体的解包操作:
接上面的例子,let person2 = person1!,这里,person2的类型就是Person类型,不再是optional类型了。
那么所谓的自动解包是在什么时候解包呢?
答案是:调用这个对象中的方法或属性的时候。比如:
test不需要解包符号,而test2后必须写解包符号。
3.关于swift引入的Computed Properties概念
今天看了Salesforce的sdk,发现了如下的demo代码:
#import "SObjectData.h" @interface SampleRequestSObjectData : SObjectData @property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *contactId;
@property (nonatomic, copy) NSString *contactName;
@property (nonatomic, copy) NSString *productId;
@property (nonatomic, copy) NSString *productName;
@property (nonatomic, copy) NSString *deliveryDate;
@property (nonatomic, copy) NSNumber *quantity;
@property (nonatomic, copy) NSString *status;
@property (nonatomic, copy) NSDictionary *authorizedUsers;
@property (nonatomic, copy) NSArray *userRecords;
@property (nonatomic, copy) NSArray *attachments; @end //
// SampleRequestSObjectData.m
// SFDCOfflinePoc
//
// Created by PAULO VITOR MAGACHO DA SILVA on 1/24/16.
// Copyright © 2016 Topcoder Inc. All rights reserved.
// #import "SampleRequestSObjectData.h"
#import "SampleRequestSObjectDataSpec.h"
#import "SObjectData+Internal.h"
#import <SmartSync/SFSmartSyncConstants.h> @implementation SampleRequestSObjectData + (SObjectDataSpec *)dataSpec {
static SampleRequestSObjectDataSpec *sDataSpec = nil;
if (sDataSpec == nil) {
sDataSpec = [[SampleRequestSObjectDataSpec alloc] init];
}
return sDataSpec;
} #pragma mark - Property getters / setters - (NSString *)name {
return [self nonNullFieldValue:kSampleRequestNameField];
} - (void)setName:(NSString *)name {
[self updateSoupForFieldName:kSampleRequestNameField fieldValue:name];
} - (NSString *)contactId {
return [self nonNullFieldValue:kSampleRequestContactField];
} - (void)setContactId:(NSString *)contactId {
[self updateSoupForFieldName:kSampleRequestContactField fieldValue:contactId];
} - (NSString *)contactName {
return [[self nonNullFieldValue:kSampleRequestContactQueryField] objectForKey:@"Name"];
} - (NSString *)productId {
return [self nonNullFieldValue:kSampleRequestProductField];
} - (void)setProductId:(NSString *)productId {
[self updateSoupForFieldName:kSampleRequestProductField fieldValue:productId];
} - (NSString *)productName {
return [[self nonNullFieldValue:kSampleRequestProductQueryField] objectForKey:@"Name"];
} - (NSString *)deliveryDate {
return [self nonNullFieldValue:kSampleRequestDeliveryDateField];
} - (void)setDeliveryDate:(NSString *)deliveryDate {
[self updateSoupForFieldName:kSampleRequestDeliveryDateField fieldValue:deliveryDate];
} - (NSString *)quantity {
return [self nonNullFieldValue:kSampleRequestQuantityField];
} - (void)setQuantity:(NSString *)quantity {
[self updateSoupForFieldName:kSampleRequestQuantityField fieldValue:quantity];
} - (NSString *)status {
return [self nonNullFieldValue:kSampleRequestStatusField];
} - (void)setStatus:(NSString *)status {
[self updateSoupForFieldName:kSampleRequestStatusField fieldValue:status];
} - (NSDictionary *)authorizedUsers {
return [self nonNullFieldValue:kSampleRequestAuthorizedUsersField];
} - (void)setAuthorizedUsers:(NSDictionary *)authorizedUsers {
[self updateSoupForFieldName:kSampleRequestAuthorizedUsersField fieldValue:authorizedUsers];
} - (NSArray *)attachments {
return [self nonNullFieldValue:kSampleRequestAttachmentsField];
} - (void)setAttachments:(NSArray *)attachment {
[self updateSoupForFieldName:kSampleRequestAttachmentsField fieldValue:attachment];
} - (NSArray *) userRecords {
int totalSize = [[self.authorizedUsers objectForKey:@"totalSize"] intValue];
if (totalSize > 0) {
return [self.authorizedUsers objectForKey:@"records"];
}
return nil;
} @end
通过代码,可以看出,声明的几个@property 其实没有对每个property对应的真实变量进行读写操作,而是通过自定义的get,set方法对其他的数据进行操作,但是系统会不会自动建立那些没用的真实变量呢?从代码上是看不出了。而且从声明的地方也看不出这些property的特殊性,不注意还真容易误解。
swift的Computed Properties,解决了这个问题:
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
这里的center,有自定义的get,set方法,就明确地指出了它的目的不是为了保存一个值,而是“provide a getter and an optional setter to retrieve and set other properties and values indirectly.”
这个写法就比以前的oc写法要好上很多啊!
4. swift中同名函数(多态?)
func test(one:NSString) -> NSString{
return "aaa"
} func test(one:Int) -> NSString{
return "bbbb"
}
上面是2个函数!他们的区别仅仅是输入参数类型不同!
5.
swift 中不叫做类属性,叫类型属性,因为在swift中,struct 和enum也是可以有这种属性的,叫类属性明显不准。
顺便复习一下,java 和 c++中类方法和类变量是用 static 关键字声明的。
static在c语言中有2个作用,写在函数体里面时,作用同上面的几种情况,表示静态的意思。但是写在函数体外边时,是防止其他全局变量同名,也阻止了外部文件对这个变量的引用。
oc 中类方法用+标记,类变量与c语言中的一样。一般而言,使用static声明,并另外写函数提供访问方法。
swift中的值类型(struct,enum)保持了这个传统,使用static关键字。但在类中发明了class这个关键字。
6.
今天写了delegate,遇到以下问题:
这里protocol的写法有问题,如果delegate指向一个实现了某个协议对象的引用,在oc里是这样写delegate的类型 id<protocol>,而在swift中,没有这种写法,应该像上面那样直接写出协议名,因此,协议声明应该这样写:
protocol MyPickerViewDelegate: NSObjectProtocol { func pickerConfirm(content:String)
}
这也是因为,除了class 外,struct和enum也能实现协议,但是他们都是值类型,不是引用类型,如果想使用weak,那么必须先让协议符合class的要求!
使用swift 中的注意,不断完善中的更多相关文章
- Swift:一个简单的货币转换器App在iOS10中的分析和完善
这本不算是一个完整的货币转换App,只不过是一个小巧的学习性质的程序.该App覆盖了如下几个知识点: 多国语言的支持 通过网络Api接口读取数据 最后我们来修复一个原来代码中的一个小错误作为完美的收尾 ...
- Mysql基础代码(不断完善中)
Mysql基础代码,不断完善中~ /* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限 ...
- php 基础代码大全(不断完善中)
下面是基础的PHP的代码,不断完善中~ //语法错误(syntax error)在语法分析阶段,源代码并未被执行,故不会有任何输出. /* [命名规则] */ 常量名 类常量建议全大写,单词间用下划线 ...
- ios - 自动布局框架编写(更多功能完善中)
之前用的storyboard以及xib挺多的,最近看到朋友用第三方框架---自动布局约束框架在添加控件约束的时候老实报错.后来自己就试了试纯代码创建以及约束控件.但是纯代码约束一个控件还可以,如果约束 ...
- Python获取会议部分的信息内容(不断完善中)
这是一个用于获取物理师会议报告的简单爬虫,数据库表结构正在不断完善中 爬虫信息: # -*- coding:utf-8 -*- import urllib.request import pymysql ...
- RAMOS (内存操作系统)-无忧百科(不断完善中)
RAMOS (内存操作系统)-无忧百科(不断完善中) - RAMOS - 无忧启动论坛 - Powered by Discuz! http://bbs.wuyou.net/forum.php?mod= ...
- Using Swift with Cocoa and Objective-C--在同个project中使用Swift和在同个project中
http://www.cocoachina.com/newbie/basic/2014/0605/8688.html watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5u ...
- linux 命令学习(持续完善中...)
linux 命令学习(持续完善中...) 主要是记录一些开发过程中用到的linux命令,慢慢补充 一.用户 1.添加用户: useradd 用户名 2.设置密码:passwd 用户名 ,然后按照提示输 ...
- 2018年最新Java面试题及答案整理(持续完善中…)
2018年最新Java面试题及答案整理(持续完善中…) 基础篇 基本功 面向对象特征 封装,继承,多态和抽象 封装封装给对象提供了隐藏内部特性和行为的能力.对象提供一些能被其他对象访问的方法来改变它内 ...
- Unity 游戏框架搭建 2019 (四十八/四十九) MonoBehaviourSimplify 中的消息策略完善&关于发送事件的简单封装
MonoBehaviourSimplify 中的消息策略完善 在上一篇,笔者说,MonoBehaviourSimplify 中的消息策略还有一些小问题.我们在这篇试着解决一下. 先贴出来代码: usi ...
随机推荐
- 后缀.jar的是什么文件?
解压kafka 打开后是一堆.jar结尾的文件,那么后缀.jar的是什么文件? JAR 文件就是 Java Archive File,顾名思意,它的应用是与 Java 息息相关的,是 Java 的一种 ...
- 修改emlog表字段名称
在em_twitter表中增加一个字段. ,添加一个字段isImportant alter table em_twitter add isImprotant ) not ; ,把字段isImprota ...
- Python画图笔记
matplotlib的官方网址:http://matplotlib.org/ 问题 Python Matplotlib画图,在坐标轴.标题显示这五个字符 ⊥ + - ⊺ ⨁,并且保存后也能显示 h ...
- R You Ready?——大数据时代下优雅、卓越的统计分析及绘图环境
作者按:本文根据去年11月份CSDN举办的“大数据技术大会”演讲材料整理,最初发表于2012年2月期<程序员>杂志. 0 R 的安装
- hdu4950 Monster (水题)
4950 Monster Monster Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...
- 密码学初级教程(六)数字签名 Digital Signature
密码学家工具箱中的6个重要的工具: 对称密码 公钥密码 单向散列函数 消息认证码 数字签名 伪随机数生成器 提问: 有了消息认证码为什么还要有数字签名? 因为消息认证码无法防止否认.消息认证码可以识别 ...
- 【AngularJS】—— 13 服务Service
在AngularJS中有很多的服务,常用的比如$http,$location等等. 本篇文章会介绍一下的内容: 1 $http这种Angular提供的服务的使用 2 如何自定义服务,并总结服务需要注意 ...
- zookeeper集群配置与启动——实战
1,准备: A:三台linxu服务器: 10.112.29.177 10.112.29.172 10.112.29.174 命令 hostname 得到每台机器的 hostname vm-10-112 ...
- nyoj 252 01串 动态规划( java)
当n=2时, 输出 3:当n=3时, 输出 5:当n=4时, 输出 8: #### 分析: 当n=4时,如 0101 符合条件, 当第一个位置是0时,还剩3个位置 ,与n=3时个数相等: 符合条件的为 ...
- 如何给wordpress外部链接自动添加nofollow
wordpress多作者博客可以丰富网站的内容,但同时也会产生一些无关的链接,例如有些投机的人会考虑在文章中随意添加外部链接,如果你不想给这些外部链接传递权重,你需要给这些外部链接加上 rel=&qu ...