swift 学习(一)基础知识 (基本数据类型,操作符,流控制,集合)

xcode 中调用API帮助

  1、查看简单信息,选中后 按键 control +左键单击  或者按 右侧属性栏 里的帮助按钮

2、完整API,选中后 按键 control +左键双击

  3、查看类、函数等的注释,参数列表等,alt +左键单击

4、代码块注释与取消注释的快捷键 都是 command + /

  5、---不能用try...catch,但可用assertion 调试,有多个重载版本,assert(useDate<=0,"不符合则报错")

swift2.0中已引入do-catch语句

正文

初步印象

  1. 字符统一用unicode编码,区分大小写,有很多类似js,java的用法

  2. 类型安全:有可选类型,可选类型的值缺失时为 nil ,不再需要对一个值判别是否为Null,变量声明时已经确定

  3. 在swift中,数字字面量之间的运算,支持隐式类型转换,但数字类型的变量和常量之间的运算,则不再支持隐式类型转换。

  4. 标示符命名规则与C相同,但是 关键字可以做标示符

  let π = 3.14  等价于 let  `π` = 3.14

  var `class`="sdd"

  5. 字符串比对时加入了更多判断。不再只是简单地比对组成字符串的标量,而是会比对最终表现形式

  6. 字符和字符串都用双引号

  7. 句末不用写分号,但多条语句写在同一行时要加

  8. 变量声明用var, 常量用let,因此变量声明格式 变化较大  ,数据类型编译器会自动识别,一般不用显式声明

    let a = 2

    var b: Double = 4

    var aInt = 4, bInt = 7

     var p1 = 10,p2:Double

  9. swift 语法内容很少,使用也很方便。而且函数是第一性的,也有全局变量,面向对象,面向过程,函数式都可以尝试。就是太多与objective-c相关的东西。

  10. 声明字典,数组用 方括号,而不是花括号, 元组 用圆括号

  11. 接口关键字改做protocal,更形象了

12. 枚举和结构的功能增强了,可以加入属性,方法,也可以实现接口

一段Swift代码(可选类型的源码)
enum Optional<T> : Reflectable, NilLiteralConvertible {
case None
case Some(T) /// Construct a `nil` instance.
init() /// Construct a non-\ `nil` instance that stores `some`.
init(_ some: T) /// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`.
func map<U>(f: @noescape (T) -> U) -> U? /// Returns `f(self)!` iff `self` and `f(self)` are not nil.
func flatMap<U>(f: @noescape (T) -> U?) -> U? /// Returns a mirror that reflects `self`.
func getMirror() -> MirrorType /// Create an instance initialized with `nil`.
init(nilLiteral: ())
} extension Optional : DebugPrintable { /// A textual representation of `self`, suitable for debugging.
var debugDescription: String { get }
}

注意点

  1、 xcode 中 swift 运算符 两边要加空格,否则多数时候会报错(赋值 和 比较)

关键字 共60个

 与声明有关的14个:class, deinit, enum, extension, func, import, init, let, protocol, static, struct, subscript, typealias, var

与语句有关的14个:break, case, continue, default, do, else, fallthrough, if, in, for, return, switch, where, while

 表达式和类型关键字12个:as, dynamicType, is, new, super, self, Self, Type, _COLUMU_ , _FILE_ , _FUNCTION_ , _LINE_

 特定上下文中使用的20个:associativity, didset, get, infix, inout, left, mutating, none, nonmutating, operator, override, postfix, precedence, prefix, rightset, unowned, unowned(safe), unowned(unsafe), weak, willset

补充:finaly private public internal dynamic

  @IBoutlet @IBAction  @UIApplicationMain @objc

  @autoclosure @autoclosure(escaping)

  @autoclosure:用在函数的里标记一个参数,然后这个参数会先被隐式的包装为一个closure,再把closure作为参数给这个函数。 从而实现对传递给这个参数的表达式延迟求值。

func myassert(@auto_closure predicate :  () -> Bool) {
#if !NDEBUG
if predicate() {
abort()
}
#endif
} //调用
myassert(someExpensiveComputation() != 42)

 

func &&(lhs: LogicValue, @auto_closure  rhs: () -> LogicValue) -> Bool {
return lhs.getLogicValue() ? rhs().getLogicValue() : false
}

 1.2 新增:@noescape:可以用在函数的闭包参数上,这意味着这个参数是唯一可被调用的(或者用在函数调用时以参数的方式出现),其意思是它的生命周期比函数调用的周期短,这有助于一些小小的性能优化,但最重要的是它屏蔽了闭包中对self.的需求。这使得函数的控制流比其他更加透明。在未来的beta版本中,标准库函数将普遍采用这种特性,比如autoreleasepool(): 

func autoreleasepool(@noescape code: () -> ()) {
pushAutoreleasePool()
code()
popAutoreleasePool()
}

 使用在函数参数上的 @autoclosure属性现在含有@noescape新属性的功能,这个改进限制了@autoclosure作为控制流程以及惰性计算的能力。

  第二种形式。@autoclosure(escaping), 和@autoclosure有着同样的调用形式,但是它允许产生结果的闭包在实现中缓存

运算符

  优先级排序:

  最高:  ++, --, !, ~, - , +

  160:   << , >>

  150:   * , / , % , & , &* , &/ , &%

  140:   + , - , &+ , &- , | , ^

  135:   ..< , ...

  132:   is , as

  130:   < , <= , > , >= , == , != , === , !==

  120:   &&

  110:   ||,??

  100:   ?:

  90:   =, *=, /=, %=, +=, -=, <<=, >>=, &=, |=, ^=, &&=, ||=

swift特点

swift 赋值运算符并不能将自身作为一个值进行返回

  if x = y {} // 报错

  println(a = 3) // ()

swift 默认情况下算数运算符不容许值溢出,需使用溢出运算符

  &+,&*: 溢出加法 用于整数 上溢出 

   var max = UInt16.max // 65535

   println(max + 1)         // 报错

   println(max &+ 1)       // 0

   var max = Int16.max  // 32767

   println(max &+ 1)      // -32768

  &-,&*: 整数下溢出

  &/, &%  解决除数为0 的情况,xcode不识别了,已经被移除

swift中可以浮点数求余

  let a = 3.667 % 1.3   // 1.067

swift 中提供了 恒等运算符===,!==,用来测试两个对象的引用是否来自同一个对象实例

可选类型与拆封运算

// nil不同于c中的NULL,它表示值缺失,而不是空指针
// 只有可选类型的变量或常量才可接受nil,非可选类型的变量或常量不能接受nil
func divide(a:Double,b:Double) ->Double? {
if(b == 0){
return nil
}
return a / b
} let result1 : Double? = divide(100,1)
println(result1) // Optional(100.0)
//强制拆封 (确定可选类型一定有值,可在读取它时通过拆封获取这个值)
if result1 != nil{
println(result1!) //100
result1?.hashValue
} //隐式拆封(更方便访问,会自动解封,若此时数据为nil,则后续操作可能出错)
let result2 : Double! = divide (100,0)
println(result2) //nil
// result2.hashValue // 报错
result2?.hashValue // nil,添加问号则如果result2为nil就不会执行后续
let result3 : Double! = divide (100,2)
println(result3) //50.0
result3.hashValue

?? 空值合并运算符

// 对 a 进行判断,如果不为 nil 则解包,否则就返回 b
// a 必须是 optional 的
// b 必须和 a 类型一致
// 相当于三目运算符的简化版
var a: String? = "a"
var b: String? = "b"
var c = a ?? b // "a" a = nil
c = a ?? b // "b"
b = nil
c = a ?? b ?? "c" // "c" //简化代码
if allowEmpty || items?.count ?? 0 > 0 {
}

区间运算符分为闭区间 (...) 和左闭右开区间 (..<)

//1...100 等同于 1..<101,区间
// 区间运算符其实返回的是一个 Range<T> 对象,是一个连续无关联序列索引的集合。 // .....
let aNumber:Int = 3
switch aNumber
{
case 0...5:
println("This number is between 0 and 5")
case 6...10:
println("This number is between 6 and 10")
default:
println("This number is not between 0 and 10")
} // .....
(1...10).map{
"$\($0)" + ".00"
} // .generate() 遍历 Range<T> 中的值。
var range = 1...4
var generator = range.generate() // {startIndex 1, endIndex 5} var item:Int?
do{
item = generator.next()
println(item)
}while(item != nil) //区间运算符返回的是一个 ClosedInterval 或者 HalfOpenInterval 的东西,
//类型只要是 Comparable 就可以了。所以我们也可以把 String 放到 ... 里。 let interval3 = 4.6...7.8
interval3.contains(4.88) // true //通过 String 的 ClosedInterval 来输出字符串中的小写字母:
let test = "Hello"
let interval = "a"..."z"
// 交集
let interval2 = interval.clamp("d"..."h") for c in test.characters {
if interval.contains(String(c)) {
println("\(c)")
}
} //e l l o

+Inf, -Inf, NAN

//let  a =  23 / 0   // 报错,0不能做除数

let b = 23.0 / 0   // inf 正无穷大
let bb = 23.0 / -0 // inf 正无穷大
let c = -23.0 / 0 // -inf 负无穷大
let cc = -23.0 / -0 // -inf 负无穷大
let d = 0.0 / 0 // nan 非数
let dd = 0.0 / -0 // nan 非数 b == bb // true
c == cc // true
d == dd // false

  

运算符重载

1. 非常实用,但也相当有风险,可读性问题,可使用字符为:/ = – + * % < > ! & | ^ . ~

2. 运算符函数即便写在类内部,定义后也会自动进入全局Global作用域,而不是作为类的一个成员函数

struct Vector2D {
var x = 1.0, y = 1.0
} // 实现结构类型Vector2D的加法
func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
func *(vector2D: Vector2D,scalar:Double)->Vector2D{
return Vector2D(x: vector2D.x * scalar, y: vector2D.y * scalar)
}
// 1.实现 组合赋值运算符 左参数要设置为inout,赋值运算没有返回值
func += (inout left: Vector2D, right: Vector2D){
left = left + right
}
// 3. 会把1,2都覆盖了,不会报错
func += (left: Vector2D, right: Vector2D)->Vector2D{
let left2 = left + right
return left2
}
// 2.也可以有返回值,与1 不能并存
func += (inout left: Vector2D, right: Vector2D)->Vector2D{
left = left + right
return left
} // 实现一个单目运算符,需要加前缀prefix或 postfix
//
prefix func -(vector2D:Vector2D)->Vector2D{
return Vector2D(x: -vector2D.x, y: -vector2D.y)
} // 1.运算结果要保存,则要用inout
prefix func ++(inout vector2D:Vector2D)->Vector2D{
vector2D = vector2D + Vector2D(x: 1,y: 1)
return vector2D
}
// 3.会覆盖1,2 。不保存运算结果,有返回值
prefix func ++(vector2D:Vector2D)->Vector2D{
let vector2D2 = vector2D + Vector2D(x: 1,y: 1)
return vector2D2
}
// 2. 没有返回值
prefix func ++(inout vector2D:Vector2D){
vector2D = vector2D + Vector2D(x: 1,y: 1)
} postfix func ++(inout vector2D:Vector2D)->Vector2D{
let _vector2D = vector2D
vector2D = vector2D + Vector2D(x: 1,y: 1)
return _vector2D
} // 非是对原有操作符的新应用,则要先声明其为操作符
prefix operator +++ {}
prefix func +++(var c: Vector2D) -> Vector2D{
c += c
c += Vector2D(x: 1.0, y: 1.0)
return c
}
/// 自定义运算符需要遵循两段式,即需要先声明运算符
/// infix / prefix / postfix
/// associativity 表示结合性:left,rigth,none,默认为none
/// 指的事和其他运算符优先级相同的情况下,是从左边开始计算还是右边
/// precedence 表示优先级的数值,0...255,默认100
/// assignment 定义组合运算符时需要用到这个,
infix operator +-{ associativity left precedence 140}
func +-(left:Vector2D,right:Vector2D)->Vector2D{
return Vector2D(x:left.x + right.x,y:left.y - right.y)
} infix operator +-={associativity right precedence 140 assignment}
func +-=(inout left:Vector2D,right:Vector2D)->Vector2D{
left = Vector2D(x:left.x + right.x,y:left.y - right.y)
return left
} var point = Vector2D(x: 3.0, y: 1.0)
var v1 = Vector2D(x: 1,y: 1)
++v1 //{x 2, y 2}
v1 //{x 2, y 2}
v1++ //{x 2, y 2}
v1 //{x 3, y 3}
-v1 //{x -3, y -3}
+++point //{x 7.0, y 3.0}
point //{x 3, y 1} v1+-point //{x 6, y 2}
v1+-=point //{x 6, y 2}
v1 //{x 6, y 2}
let v3 = v1 += point
v3
v1

数据类型

swift中,不同于c,java等的基本数据类型那样单纯表示数值,

swift中 基本数据类型和集合全部由结构或枚举实现,虽然牺牲了性能,但是功能却强大了很多。

基本数据类型

  • 整型(Int8,Int16,Int32,Int64,Int(32位平台与Int32等宽,64位平台与Int64等宽),UInt8,UInt16,UInt32,UInt64,UInt)
  • 浮点型(Float, Double)float 32位,double64位,默认浮点数为double
  • 字符 let a:Character = "&"  let b = "\u{1fb03}"   字符也用双引号
  • 字符串  字符串拼接 let number = 9 ; let total = "\(number)加10等于\(Double(number) + 10)"
  • 布尔型 Bool 只有两个值true,false,不能用0,1代替

元组(tuple)类型(记录)

  var student1 = ("1001","张飞",20,96) 或 var student2 = (id:"1001",name:"张飞",age:20,score:96)

  或 var  student3 : (String,String,Int,Int) ; student3 = ("1001","张飞",20,96)

  访问元组字段: student1.0, student2.0,student2.id

枚举

结构

typealias MyInt = Int
var x :MyInt = 10

swift 中除类以外,所有基本数据类型,集合都是由结构实现,所有都可以调用构造器来初始化

let x = Float() //0.0
let y = Double() //0.0
let z = Int() //0
let aa = Bool()//false
let bb = Character("S") //Character没有无参初始化
let dd = String() //""
let ee = [Int]()//0 elements
let ff = [Int:String]()//0 key/value pairs
let gg = Set<String>() //0 members
let xxx: () = ()

swift里除了类以外的基本类型都是由结构体实现的,也既是除了类以外都是值引用类型

不再支持数字类型的隐式转换

let pi = 3 + 0.1415926    // pi的类型推导为double(最大精度匹配原则)

let anInt = 10
let aDouble = 3.14
//var result = anInt + aDouble //报错
var result = Double(anInt) + aDouble let aChar:Character = "a"
//var a:Character = anInt + aChar //报错
//var b:Int = a //报错
  • Int8.min,Int8.max
  • 二进制:0b,八进制:0o,十六进制:0x,指数:1.56e-2; 十六进制指数 0x5.a2p2(0x5.a2 * 22)
  • swift 为方便阅读,整形,浮点均可添加多个零或下划线以提高可读性 var a = 000.0145 ; var b = 3_360_000
// 整形

let a = 100
a.byteSwapped
a.bigEndian
a.littleEndian
a.toIntMax()
a.value
a.advancedBy(100)
a.description

字符Character,字符串String 都使用""

 String 本质上是一个Struct,因此可以用构造器来创建字符串

var str1 = "2sfer"
var str2 = String()
var str3 = String(count:5,repeatedValue:Character("f"))
let character:Character = "a"
let str4 = String(character)
let characters:[Character] = ["c","b","a"]
let str5 = String(characters)

字符串日常操作:是否包含某字符,rangOfString,前后缀,大小写切换,分割等

let someone = "Joris Kluivers"

let end2 = someone.rangeOfString(" ")//5..<6
if (end2 != nil) {
let firstName = someone[someone.startIndex..<end2!.startIndex] //"Joris"
} else {
// no space found
} // 前后缀
let doc = "Java.docx"
if doc.hasSuffix(".docx"){}
if doc.lowercaseString.hasPrefix("java"){} // 大小写
"Hello, playground".uppercaseString //HELLO, PLAYGROUND
"Hello, playground".lowercaseString //hello, playground // 分割
"Hello, playground".componentsSeparatedByCharactersInSet(
NSCharacterSet(charactersInString: "eo")
) //["H", "ll", ", playgr", "und"]
"Hello, playground".componentsSeparatedByString("play")//["Hello, ", "ground"]
var cafe = "cafe"
// 插入字符
cafe.insert("!", atIndex: cafe.endIndex) // "cafe!"
// 插入字符串
cafe.insertContentsOf(" is delicious".characters , at: cafe.endIndex.predecessor())//"cafe is delicious!" //移除字符
cafe.removeAtIndex(cafe.endIndex.predecessor()) // "!"
//移除字符
cafe.removeRange(cafe.startIndex.advancedBy(1)...cafe.startIndex.advancedBy(3))// "c is delicious" //替换 ,移除字符单位置还在
cafe.replaceRange(cafe.startIndex.advancedBy(1)...cafe.startIndex.advancedBy(3), with: "afe") //"cafe delicious"

swift中每一个字符都代表了一个可扩展字母集(Extended Grapheme Clusters)

每一个可扩展的字母集,又由一个或几个有序的Unicode标量的值(Unicode scalar value)所组成,以上这些构成了人类可读的字符。

//形同c中用ascii编码,swift用unicode编码,
一个unicode标量占21个bit,
取值范围,U+0000到U+D7FF和从 U+E000 到U+10FFFF,不包括 U+D800 到 U+DFFF
let dollarSign = "\u{24}"
let blackHeart = "\u{2665}"

String 用结构实现,是值类型,而NSString 用类实现,是引用类型

String.Characters.count,和 NSString.length 并不总是完全一样的值,因为前者统计的是有意义的Extended Grapheme Clusters 个数,后者是UTF-16编码 计数

var word = "cafe"
word.characters.count // 4
(word as NSString).length // 4 word += "\u{301}" // "café", 组合了一个重音符号
word.characters.count // 4
(word as NSString).length // 5 word += "\u{301}" // "café́", 再组合了一个重音符号
word.characters.count // 4
(word as NSString).length // 6 word += "\u{301}" // "café́́", 再组合了一个重音符号
word.characters.count // 4
(word as NSString).length // 7 word += "\u{301}" // "café́́́", 再组合了一个重音符号
word.characters.count // 4
(word as NSString).length // 8 word += "\u{301}" // "café́́́́", 再组合了一个重音符号
word.characters.count // 4
(word as NSString).length // 9 word += "\u{20dd}" // "café́́́́⃝", 再组合了一个圆
word.characters.count // 4
(word as NSString).length // 10 var decomposed:Character = "\u{1112}\u{1161}\u{11ab}" // "한" 由三个Unicode标量组成,但是一个字符 var decomposedString:String = "\u{1112}\u{1161}\u{11ab}" // 用 for in 遍历字符串
for c in decomposedString.characters{
print(c) // "한", 只有一个字符
} //用下标遍历
let end = decomposedString.endIndex // 3 最后一个Unicode标量的位置+1
var i = decomposedString.startIndex // 0
i.advancedBy(1) // 3 for(var j = decomposedString.startIndex;j<end;j=j.successor()){
print(decomposedString[j])
} let NSdecomposedString = decomposedString as NSString
for var i = 0; i < NSdecomposedString.length; i++ {
//3 times (4370, 4449, 4523)
print(NSdecomposedString.characterAtIndex(i))
} let u1 = UnicodeScalar(4370) // 4370
let u2 = UnicodeScalar(4449) // 4449
let u3 = UnicodeScalar(4523) // 4523
let c1 = Character(u1) // ᄒ
let c2 = Character(u2) // ᅡ
let c3 = Character(u3) // ᆫ
let c = Character("\(c1)\(c2)\(c3)") // 한

swift中字符串的比较会 比对每个字符的语义和最终表现形式。而不是比对构成字符的标量

let word1 = "caf\u{e9}"         // "café"  \u{e9} 带音调的拉丁字母e
let word2 = "caf\u{65}\u{301}" // "café" \u{65}\u{301} 拉丁字母e + 一个重音符号
word1 == word2 // true
// 转化为 NSString 后比对
(word1 as NSString) == (word2 as NSString) // false let a1 = "\u{41}" // 拉丁字母 A
let a2 = "\u{0410}" // 斯拉夫字母 A
a1 == a2 // false

子字符串:无法用Int下标来访问String中的字符或字串,而使用String.Index

var imageStr = "												

	
	
上一篇:【2016-10-20】【坚持学习】【Day10】【反射2】


下一篇:Eclipse Debug