Swift是强类型语言,所有变量都是强类型
传递参数时候,只要传递的参数不是类或者类的实例,那传递过的参数都是拷贝过的,即都是值;字典和数组在swift中是结构体。不是类,结构体和类两大区别:
1,结构体不能继承,而类可以
2,结构体传递的是值,而类传递的是引用。
常规的数组声明:Array<类型>(),例如:
var test2 = Array<Double>()
test2.append(10)
test2.append(100)
print(test2)//输出[10.0, 100.0]
或者在方括号内写入类型来声明数组,例如:
var test = [String]()
test.append("test1")
test.append("test2")
print(test)//输出[“test1", "test2"]
常规的字典声明: Dictionary<key, value>() 例如:
var knowOps = Dictionary<String, Int>()
或者以[key:value]的方式声明,例如上式等同于:
var knowOps = [String:Int]()
但函数需要多个参数并使用闭包时,只有最后一个参数可以写在括号外,其余还是括号内
在swift中,允许方法名相同,但是参数必须不同
Required关键字
在函数前面加Required,则子类必须实现该函数
NSFileManager.defaultManager()返回默认实例,只能在主线程使用,若需要在其他线程使用,需要新建一个NSFileManager实例,例如:
let manager = NSFileManager()。
一个线程只有一个NSFileManager实例,当前线程的NSFileManager实例不能在其他线程使用
var 声明的为变量,let为常量,常量只能赋值一次
后面确定不再赋值的最好用let
变量和定量声明时候都需要声明类型,如果不声明类型那就需要直接赋值
例如:
var test:Int
var test = 1
var test (报错)
变量和定量声明之后都可以不用赋值,但不能为nil,声明用『!』的变量或常量,不能被nil赋值(输出则程序奔溃,但可以编译),声明用『?』的变量或常量可被nil赋值(输出也不会奔溃)
例子:
var test: Int?
test = nil
print(test)//输出nil
var test: Int!
test = nil //这一步可以正常运行但没有赋值到
print(test) //程序奔溃
声明类型用『!』,后面取值不用加『!』
例如:
var test:Int
var test2:Int = test +1
若是用『?』,则后面取值要加『!』。赋值的时候不用加
例如:
var test:Int?
vat test2:Int? = test!!+1
test2 = 10
布尔值
Swift为布尔量提供了两个常量值, true 和false 。
元组
声明格式: var aTupe =(”A”,2) ——无标签,通过索引取值
例如:var test = aTupe.0 ——————test ==“A”
声明格式:let bTupe = (first:”one”,second:”two”) ———通过前置标签取值
例如:let test = bTupe.first ——————test ==“one”
特殊用法;
let http404Error = (404, "Not Found")
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)") //The status code is 404
数组
声明例子: let test :[Int] = [1,2,3,4]
var test2 = ["a","b","c"]
let test3 = [Int]() //不为空,count = 0
let test4: [Int]? // 此时为空
常规方法:
array.insert(2, atIndex: 0) //索引0插入2
array.append(4) //后面加上4
array.removeAtIndex(4) //移除索引为4的值
字典
声明例子: var dic = ["fiest":"one", "sencond":2]
赋值: dic["thid"] = 4
//dic此时为["fiest": one, "sencond": 2, "thid": 4]
取值 : dic.first!
//比较特别的例子:
var dic = [“key”: “value”]
dic str1: String?
str1 = nil
dic[“key”] = str1
//此时dic[“key”]是存在的,值为nil,可以输出dic[“key”: nil]
var dic2 = [“key”: “value”]
dic2[“key”] = nil
//此时dic2[“key”]是不存在的,即成功删除 key-value键值对
注意:
当 Dictionary 的 value 类型为 String时,如果你要设置它的值,它接受的是一个 String?类型的参数
for循环
例子:for obj in 1..<10 {
num++
}
for obj in 1…10 {
num++
}
for var obj = 1; obj < 10; obj++ {
num++
}
//…表示1~10,..<表示1~9
switch
格式:switch XX {
case a:
//a必须与XX同类型
//需要执行的内容
//不需要break结尾
case b:
//同上
default:
//必须实现default,
}
类别名 typealias
用于给已存在的类取其他名字
例如:
typealias myInt = Int
var test2:myInt! //此时myInt相当于Int
test2 = 5
//函数类型也可以作为别名
例子: typealias intFunction = Int -> Int
断言 assert(条件)
例子: let age = -3
assert(age > 0)
print("next") //此时没有输出next,因为条件不符合
//代码执行只要在 if age >= 0 评定为 true 时才会继续,就是说,如果 age 的值非负。如果 age 的值是负数,在上文的代码当中, age>= 0 评定为 false ,断言就会被触发,终止应用。
函数
基本格式: func 函数名(参数列表) -> 返回类型 {
//code
//可以在里面继续添加函数(方法)
}
例子: func myMethod2 (var firstName fitst: Int,var second: Int) ->NSString {
func myMethod2_c (one: Int, two: Int) ->Int {
return one+two
}
fitst = myMethod2_c(1, two: 1)
return "yes:\(fitst),\(second)";
}
//(var firstName fitst: Int,var second: Int) 表示第一个参数名字为firstname,第2个参数没有设置名字则默认为second,
// myMethod2(firstName: 1, second: 1) 为调用时候的格式
//firstName就是外部名字,first就是内部名字
//当返回类型为void的时候不填写返回参数
例子:
func getAll() {
}
当函数作为变量的时候
格式: var 名字:(类型) ->返回类型
//当返回类型为空的时候,则为返回类型=()
例子: var myMethod:(Int) ->()
继承
格式 : class XX : DD {
override init (){
//code
}
convenience init(参数列表) {
self.init() //这步是必须的
//code
}
deist {
//当retaincount=0的时候运行该函数
//释放内存的工作
}
}
例子: class animal {
var name: NSString?
var sex: NSString?
init(){
print("create animal")
}
}
class Dog: animal {
var all:NSString? {
return "name : \(self.name) ,sex: \(self.sex)"
}
override init (){
print("dog create")
}
convenience init(name: NSString) {
self.init() //必须的一步
//其他初始化工作
}
//重载初始化函数
init(name: NSString, sex: NSString){
super.init() //如果下面要使用父类成员,则此步是必须的
self.name = "a"
print("!!")
//若前面不执行 super.init(),则在子类init执行完毕后,才会自动执行父类init(),之后就可以使用父类的成员
}
}
//当重载的init与需要调用原来的init时候,需要在前面添加convenience
//若父类有重载init方法,则子类中的init方法必须调用父类的重载方法
//顺序:先初始化子类自己的成员,在调用父类对应的初始化方法
//特别注意:只有类的成员方法才能引用self来表示调用该成员方法的对象引用,闭包对象(成员)不能用self
变量可重写get和set方法,不写就要初始值
例子:
class Rectangle {
var wid: Double = 0
var hei: Double = 0
var area: Double {
get {
return wid * hei
}
set {
wid = sqrt(newValue)
hei = newValue
}
}
}
其他用法:
class Rectangle {
var wid: Double = 0
var hei: Double = 0
var area: Double {
get {
return wid * hei
}
set {
wid = sqrt(newValue)
hei = newValue
}
}
var sum: Double = 0 {
willSet(new) {
print("new is :\(new)")
}
didSet(old) {
print("did set is :\(old)”)
}
}
}
// var test:Rectangle = Rectangle()
test.sum = 10
print(test.sum)
//输出以下语句: new is :10.0
did set is :0.0
10.0
//get,set和didSet,willSet不能共存
//希望同时使用get,set,didiSet,willSet,只需要重写属性成员即可,如下:
class ClassA {
var num: Int {
get {
print("get")
return 100
}
set {
print("set")
}
}
init() {
num = 0
}
}
class ClassB: ClassA {
override var num: Int {
didSet{
print("didiset")
}
willSet{
print("will set")
}
}
}
//输出顺序分别是:will set
set
didiset
get
惰性加载 lazy :在引用到的时候才开始创建
例子:
class animal {
init() {
print("animal is create")
}
}
class Dog {
var animal1 = animal()
lazy var animal2 = animal ()
init() {
print("dog is create")
}
}
引用: var dog = Dog()
print("我是分割线")
print("i am \(dog.animal2)")
输出情况
animal is create
dog is create
我是分割线
animal is create
i am one.animal
ps:只有var才能使用lazy特性
协议 protocol
继承协议的类或结构体,必须声明好protocol所有方法和函数
例子:
class Jo: Book {
var name: NSString = "jo"
var age: Int = 10
mutating func getAll( first: NSString) {
print(first)
}
}
protocol Book {
var name: NSString {get} //该属性必须可以获取
var age: Int {set get} //该属性必须可获取和设置
mutating func getAll(var first: NSString) ->() //必须存在该函数
}
//协议内声明的属性必须用{ }标注set或者get,不能为空
//一般情况下,在protocol声明后加:@class,表示该协议只能被class遵守,struct和enum等不能遵守,此时才能使用weak delegate
eg: protocol Book:class (此时协议不能使用mutating声明)
//或者使用@objc的方式,例子:
@objc protocol UIScrollViewDelegate {
optional func scrollViewDidScroll(scrollView: UIScrollView)
optional func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView
//若协议中存在属性成员,则子类也需要用@objc关键字声明该属性成员
//optional表示可选
…
}
//所有属性都只能用var,不能用let
//协议方法都用mutating声明
//mutating作用:为了能在方法中修改struct或enum的变量.
例子:protocol MyProtocol {
var myColor: UIColor {get set}
mutating func change() -> ()
}
struct MyTest:MyProtocol {
var myColor: UIColor = UIColor.redColor()
mutating func change() {
myColor = UIColor.yellowColor()
}
}
//如果去掉mutating则编译无法通过
结构体:当你不设置初始化函数时候,会默认得到一个将所有属性作为参数的初始化方法,例如:
struct MyStruct {
var x:Int = 42
var y:String = “moltuase”
init(x:Int, y: String) //默认初始化方法
}
ps:结构体可以重写init,可以有多个init(参数列表要不同)
扩展:添加额外的方法(扩展后的方法或属性都是默认实现的)
格式 :extension类型名 {
//添加需要的方法或需要的额外属性
}
例子:
extension Int {
//额外的属性
var doubled :Int {
return self * 2
}
// 额外的方法
func everything () ->() {
print("i am \(self)")
}
}
//可另外创建一个swift文件,在该文件进行扩展
//使用的时候不要import该文件,会自动添加到每个该类型的对象实例中
//扩展还可以实现协议
//尾随闭包
func someFuntion(firstName first:( str:String) -> String) ->String{
var name = first(str: "book")
return name
}
使用: var name = someFuntion { (str) -> String in
return str+"Jo"
}
//name = bookJo
上式等同于 : var name = someFuntion {
return $0+"Jo"
}
提示:如果函数的 body只有一行,则可以把 return 关键字省略了
//匿名闭包
let textLabel = {
Void -> UILabel in
let label = UILabel.init(frame: CGRectMake(150, 80, 30, 40))
label.textColor = UIColor.yellowColor()
label.text = "text"
view.addSubview(label)
return label
}()
等同于:
let textLabel:UILabel = {
let label = UILabel.init(frame: CGRectMake(150, 80, 30, 40))
label.textColor = UIColor.yellowColor()
label.text = "text"
view.addSubview(label)
return label
}()
也等同于:
let textLabel:UILabel {
let label = UILabel.init(frame: CGRectMake(150, 80, 30, 40))
label.textColor = UIColor.yellowColor()
label.text = "text"
view.addSubview(label)
return label
}
//隔离代码,并同时进行赋值,让代码更加简洁
//函数返回函数
func sumSet(var sum sum: Int) -> ( sum_: Int) -> Int {
var all = 0
func sumAdd( sum_: Int) -> Int {
return all + sum_ + sum //sumAdd的返回
}
return sumAdd //sumSet的返回
}
使用: var function = sumSet (10) //int -> Int的Function
var all = function (10)
//all = 20
柯里化(currying)
func someFuntion2(test: Int)( str:String) -> String {
return "test:\(test), str:\(str)"
}
使用: let function = someFuntion2(1)
//function 为一个string -> String的Function
let str = function(str: "2")
//str
函数内修改 :inout
在方法/函数的参数声明时候使用关键字:inout,可是传入的参数在方法/函数内同步修改
例子:
func someFuntion3( inout test: String) -> () {
test = test + "!!!!"
}
var str = "a"
someFuntion3(&str)
//str此时等于a!!!!
默认参数
在类型声明后直接赋值
例子:
class Vector2D {
var x: Int?
var y: Int?
init (x: Int = 5, y: Int = 5) {
self.x = x
self.y = y
}
}
提示:当前有默认参数的时候,调用该方法的时候可以不写参数
例子:class MyClass {
func testPrint(test1: String = "book", test:String = "test") {
print("test = \(test1)")
print("test = \(test)")
}
}
let test = MyClass()
test.testPrint()
//输出:test = book
test = test
单例
例子:
class MyManager {
var num: Int?
var sum: Int?
private static let sharedInstance = MyManager()
class var shareManager : MyManager {
return sharedInstance
}
}
使用:let manager = MyManager.shareManager
manager.num = 10
获取对象类型 object_getClass()
例子: var test = 1
print("\(object_getClass(test))") //__NSCFNumber
判断(比较)对象类型 is
例子: var test = 1
if test is Int {
print("yes")
}
//yes
KVC
例子:
class MyClass:NSObject {
dynamic var date = NSData()
dynamic var num = 0
}
private var myContext = 0
var myObj: MyClass!
override func viewDidLoad() {
super.viewDidLoad()
myObj = MyClass()
myObj.addObserver(self, forKeyPath: "num", options: .New, context: &myContext)
self.myObj.num = 1
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
print("触发该方法")
}
//
//dynamic只能用于类成员,指明它们需要动态派发,此时才能使用kvc
//需要一个子类,继承自NSObjec(只有继承之NSObject的类才能使用kvc)
//设置对应的key path(需要观察的成员名)
比较指针(内存地址是否相同),使用『===』,该操作符用于判断两个AnyObject是否为同一个引用
例子:
var str1 = "a" as AnyObject
var str2 = "a" as AnyObject
if str1 === str2 {
print("指针相等")
}
if str1.isEqual(str2){
print("内容相等")
}
//输出:内容相等
var str1 = "a" as AnyObject
var str2 = str1 as AnyObject
if str1 === str2 {
print("指针相等")
}
if str1.isEqual(str2){
print("内容相等")
}
//输出:指针相等
内容相等
//在swift中,单纯比较内容是否相等,使用==即可,如果是NSObject类型,则使用isEqual:
遍历数组 enumerate
例子: let test = [1,"a",2,"b",3,4]
for (idx,num) in test.enumerate(){
print((idx,num))
}
//输出:(0, 1)
(1, a)
(2, 2)
(3, b)
(4, 3)
(5, 4)
为数组元素添加新的东西:map
例子: let name = ["1","2","3","4"]
let member = name.map{
"成员" + $0
}
//["成员1", "成员2", "成员3", "成员4"]
对数组的元素按照某种规则增减: reduce
例子: let array = ["B","O","O","K"]
let brr = array.reduce("Jo"){
print("$0:\($0)")
print("$1:\($1)")
print("________")
return $0 + $1
}
print("brr :\(brr)")
输出:
$0:Jo
$1:B
________
$0:JoB
$1:O
________
$0:JoBO
$1:O
________
$0:JoBOO
$1:K
________
brr :JoBOOK
例子2:
let arr = [1, 2, 4]
// arr = [1, 2, 4]
let crr = arr.reduce("") {
if $0 == "" {
return String($1)
} else {
return $0 + " " + String($1)
}
}
// crr = "1 2 4"
按照一定规则进行筛选:filter
例子:let arr = [1, 2, 4]
// arr = [1, 2, 4]
let brr = arr.filter {
$0 % 2 == 0
}
// brr = [2, 4]
加锁和解锁 lock
swift不存在@synchronized()的用法,但可以使用objc_sync_enter()和objc_sync_exit()达到相同的效果
例子:
func mymethod(myObjc: AnyObject) {
objc_sync_enter(myObjc)
//在enter和exit之间myObjc不会被其他线程改变
objc_sync_exit(myObjc)
}
随机数生成 arc4random_uniform(_:UInt32) ->UInt32
例子: let dicefacecount: UInt32 = 6
var test = Int(arc4random_uniform(dicefacecount))
print(test)
//生成0~5的数字
//不使用arc4random,因为在苹果5或者以下设备中,有时候会崩溃,请注意!是『有时候』!
//最佳实践如下:
func randomInRange(range: Range<Int>) -> Int {
let count = UInt32(range.endIndex-range.startIndex)
return Int(arc4random_uniform(count)) + range.startIndex
}
使用: print(randomInRange(1...6)) //输出1~6的任一数字
错误(报错)提醒 fatalError
抛出错误,显示提示信息或者注意信息
例子:
class BaseClass {
func baseMethod() {
fatalError("basemethod必须要重写")
}
}
class YourClass: BaseClass {
override func baseMethod() {
print("重写了")
}
}
class ThisClass: BaseClass {
}
使用: let test = YourClass()
test.baseMethod()
let test1 = ThisClass()
test1.baseMethod() //在此处崩溃
操作符 『??』,如果??左侧表达式的值不为nil,则使用左侧表达式的值,若为nil,则使用右侧表达式的值。
例子:
let value = self.array ?? self.dictionary
范型
例子:func funcBuild<T, U, V>(f: T -> U, _ g: V -> T)
-> V -> U {
return {
f(g($0))
}
}
let f3 = funcBuild({ "No." + String($0) }, {$0 * 2})
f3(23) // 结果是 "No.46"
func myFunc<T,U> ( first: T, second: U) -> U {
print("first :\(first)")
let myRet: U = second
return myRet
}
let fitst = ["name" : "name"]
let second = [1,2,3]
let myStr = self.myFunc(fitst, second: second)
print("str: \(myStr)")
//输出: first :["name": "name"]
str: [1, 2, 3]
swift规范写法:
例子:if n.isNumber {
// Use n here
} else {
return
}
改成:
guard n.isNumber else {
return
}
// Use n here
使用闭包函数初始化成员时,如要在闭包函数中使用类成员,需要在声明的成员加上lazy
例子:
lazy var centerButton: CenterButton = {
let button: CenterButton = CenterButton.init(frame: CGRectMake(0, 0, self.centerButtonSize!.width, self.centerButtonSize!.height), type: self.centerIconType!)
return button
}()
避免循环引用: 引用的代码前面添加 [weak self] in
eg:
class TestClass {
var name: String?
lazy var printName: () -> () = {
[weak self] in
print("\(self!.name)")
}
init(name: String) {
self.name = name
}
deinit {
print("name:\(self.name) deinit");
}
}
使用:
test = TestClass(name: "book");
test?.printName()
test = nil
输出:
Optional("book")
name:Optional("book") deinit
限制扩展,关键字: where self: protocol
例子:
protocol Jo {
var name: String { get set}
}
protocol EnglishName {
var egName: String {get set}
}
extension EnglishName where Self: Jo {
func printNmae() -> () {
print("name: \(self.name)")
}
}
struct Test: EnglishName, Jo {
var name: String
var egName: String
}
//输出:name: Jo
//只有继承Jo,才有printNmae函数
判断对象是否为空,可以使用赋值创建的方式,例如:
if let image = UIImage(named: “foo”)
{ // image 如果创建成功,走这里
} else
{ // 如果不存在foo图片,创建失败,则走这里
}
或者:
var dic: Dictionary<String,String>?
if let dic2 = dic {
print("??")
} else {
print("!!!")
}
输出:”??”
关键字:@IBDesignable和@IBInspectable,可以支持实时渲染到界面,注意必须是UIView或者NSView的子类
例子:
import UIKit
@IBDesignable
class TestView: UIView {
var testBtn: UIButton = UIButton.init()
@IBInspectable var btnColor: UIColor = UIColor.redColor()
@IBInspectable var btnFrame: CGRect = CGRectMake(50, 50, 100, 100)
override func layoutSubviews() {
super.layoutSubviews()
self.testBtn.frame = btnFrame
self.testBtn.backgroundColor = btnColor
}
override init(frame: CGRect) {
super.init(frame: frame)
self.testBtn.frame = btnFrame
self.testBtn.backgroundColor = btnColor
self.addSubview(self.testBtn)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//提示:重写layoutSubviews(),并在其中加入对应IBInspectable声明的变量属性,才可以动态改变界面的效果