iOS开发之Swift基本语法详解

Swift语言简介

2010 年 7 月,苹果开发者工具部门总监 Chris Lattner(克里斯·拉特纳)开始着手Swift 编程语言的设计工作,用时一年时间,完成开发语言基本架构,经历了4年的开发周期,终于在2014 年 6 月Apple WWDC 发表,用来撰写 OS X 和 iOS 应用程序等。

Swift较Objective-C优点 ?

  1. 快速、现代、安全、互动,而且明显优于 Objective-C语言;
  1. 取消了 Objective-C 的指针及其他不安全访问的使用;
  2. 舍弃 Objective C 早期应用Smalltalk的语法,全面改为 句点表示法
  3. 提供了类似 Java 的命名空间(namespace)、泛型(generic)、运算对象重载(operator overloading)等新概念。

基本知识点详解

常量与变量
  • let声明常量,var声明变量,打印print()
  • 枚举类型:枚举名称点枚举值(点语法表示)
  • 常量、变量可用任何字符表示,常量必须在定义时初始化, 否则会报错
  • 每行语句后不需添加分号(添加也正确),若是多条语句则需添加分号区别
  • 若在定义的同时并初始化 – 没有必要指定数据类型,若定义时没初始化 – 必须指定数据类型
  • 常量、变量名不能包含数学符号、箭头、保留的/非法的Unicode 码位、连线与制表符、也不能以数字开头,但可在常量、变量名其他地方包含数字
  • Swift对数据类型要求非常严格,若要转换,则必须显示转换;
    • 小数默认是Double类型
    • 整数默认是Int类型
var 2x = 50   //错误
var 🐶 = 100 
var 欢迎 = 500
let num:Int = 10 //显示指定类型
let sum = num + Int(num2) //显示转换(不存在隐式转换)
逻辑分支
  • if语句不存在“非零即真”概念 条件只能放BOOL值/(true、false)
  • 三目运算符:可以if ... else 语句转换而来,保持了和OC的一致
  • if语句条件的()可以省略,{ }不能省略
  • for循环 for ... in ... { ... }0..<10 -> 0~9,0...10 ->0~10
for _ in 0..<10 {
    print("hello")  //_代表忽略
}

var a = 10
while a < 10 {
    print(a)
    a++ // ++ 前面的空格不能省略
}

//do~while在Swift2.0之后变为 repeat { ... } while(...), do用于捕捉异常
var b = 10
repeat{
print(b)
b++
}while b < 10
/**
*  switch 后面()可以省略 ,每条语句后面不需添加break,在case语句内添加变量不需{}
* default语句必须放在最后,且大部分情况下不能省略
*/
switch num{
case 1:
    print("1")
case 10:
    print("10")
case 15:
    print("15")
    let value = 15
default:
    print("0")
}

//条件绑定
var point = (100, 10)
switch point{
    //只有where后面的条件表达式为真才赋值并执行case后的语句
    case var(x, y) where x > y: 
        print("x= \(x) , y= \(y)")
    default:
        print("Other")
}

//值绑定
var point = (1, 10)
switch point{
    case (var x, 10): //会将point中X的值赋值给X
        print("x= \(x)")
    case (var x, var y): //会将point中X、Y的值赋值给X、Y
        print("x= \(x) y= \(y)")
    case var( x, y):
        print("x= \(x) y= \(y)")
    default:
        print("Other")
}

var point = (10, 15)
switch point{
    case (0, 0):
        print("坐标在原点")
    case (1...10, 10...20): // 可在元祖中再加上区间
        print("坐标的X和Y在1~10之间")
    case (_, 0): // X可以是任意数
        print("坐标的X在X轴上")
    default:
        print("Other")
}
  • C语言和OC并没有真正的Bool类型(类似非0即真),Swift引入了真正的Bool类型(Bool true false)
  • 元祖:将多个相同或者不同类型的值用一个小括号括起来,是复合类型, 小括号中可以写任意类型
//有了元祖之后就可以实现让一个函数返回多个值
let (name1 , age1 , _) =  ("chongzone", 50, 25) //利用_通配符来忽略提取
print(name1);print(age1)

//元祖的其它定义方式: 
let (name , age , score) =  ("chongzone",  50, 25)
print(name);print(age);print(score)

//指明应用元祖元素的名称
let student2 = (name:"chongzone",age:50,score:99)
print(student2.name);print(student2.age);print(student2.score)

let student = ("chongzone", 50, 55)
let student1: (String, Int, Double) = ("chongzone", 50, 55)
print(student);print(student.0);print(student.1);print(student.2)
  • 可选项(optional) – 直接打印可选类型,则会被optional包囊
  • 对于可选项,可使用 来强制解析,若是可选项没有值再做类型转换,会导致程序崩溃
  • 解决办法 – 可选绑定let + 常量 = 可选项
  • ??是一个非常有用的操作符,能够快速对nil进行判断,若对象是 nil,则使用 ?? 后面的值代替前面的 nil 值参与计算,在使用?? 时,前面的整个部分需要使用 () 包装
let url = NSURL(string: "www.baidu.com")
let request = NSURLRequest(URL: url!)
//解决办法 - 可选绑定
if let urlNormal = url {
    print(urlNormal)
    let request = NSURLRequest(URL: urlNormal)
}
  • 数组、字典、字符串
//定义数组时若指定保存对象的类型,则不能向数组添加其他类型内容
let arr = ["1","2"]
var arr2 : [String]  //或是 var arr2 = [String]() //只能保存字符串对象
arr2 = ["1"]
arr2.append("2")

var dict = ["name":"chong","age":25]
//利用元祖类型遍历字典,则会将字典内的key赋值给元祖中第一个变量,字典的value赋值给元祖中第二个变量
for (key, value) in dict {
    print(k)
    print(v)
}

//合并字典
var dict2 = ["sex":"man"]
for (k, v) in dict2 {
    dict[k] = v
}

//格式化字符串
let name = "chong"
let age = 10
var str4 = "name = \(name),age = \(age)"
var str5 = String(format: "%@, %04d", arguments: [name, age])

////遍历字符串 可直接遍历
var str6 = "chongzone is 25 la"
for st in str6.characters {
    print(st)
}

//截取 建议转化OC操作
var str7 : NSString = "chong is 30 lo"
var str8 = "chong is 30 la" as NSString
var subStr = str7.substringWithRange(NSMakeRange(3, 10))
  • 函数(四种类型)
//没参数没返回值
func sum4() {
    print("hello")
}

//存在参数没返回值
func sum2(a: Int, b: Int) {
    print(a + b)
}

//没有参数与存在返回值
func sum3() -> Int {
    return 20
}

//存在参数与返回值
func sum(a: Int, b: Int) ->Int {
    return a + b
}

//对于存在的参数,可以添加标签
func sum5 (one a: Int, two b: Int) ->Int {
    return a + b
}
print(sum5(one: 10, two: 10))
  • 闭包、函数
//Swift方法/函数 参数在前 类型在后
    /**
     *  闭包 类似于 block,闭包是定义函数的, Swift中函数就是一种特殊的闭包
     *  闭包的使用和block一样, 用于保存一段代码, 用作回调, 用作执行耗时操作
     *  定义闭包格式 -  闭包名:形参 -> 返回值类型
     *  调用闭包时格式:
     *  {
     *   (参数) -> 返回值类型
     *   in
     *   执行语句
     *  }
    */

//闭包的返回值
//Swift 不建议使用self,不同数据类型不能参与计算
override func viewDidLoad() {
        super.viewDidLoad()
       //调用重构后的函数
        let sc = createScrollView({ () -> Int in
            return 10
            }) { (index) -> UILabel in
                let width = 45
                let label = UILabel()
                label.backgroundColor = UIColor.greenColor()
                label.textColor = UIColor.darkGrayColor()
                label.font = UIFont.systemFontOfSize(17)
                label.text = "text\(index)"
                label.frame = CGRect(x: index * width, y: 0, width: width, height: 44)
              /**
                * 闭包内部, 为了能够准确定位到view, 所以在闭包内部代码需要写self
                * Swift开发中不建议写self, 一般是在闭包内才使用
                * "weakSelf!" 强制其存在 (weakSelf是可选类型 需要‘!’保证其一定不是nil)并且防止了其循环引用
                */
                weakSelf!.view.backgroundColor = UIColor.redColor()
                return label
        }
        view.addSubview(sc)
    }
    
    //2个参数都是闭包,定义闭包后一般都会在本函数内部都会调用该闭包实现
    func createScrollView(labelCount: ()->Int, labelWithIndex: (index:Int)->UILabel) -> UIScrollView{
        // 1.创建UIScrollView
        let sc = UIScrollView(frame: CGRect(x: 0, y: 100, width: 375, height: 44))
        sc.backgroundColor = UIColor.orangeColor()
        //labelCount():调用外部实现的闭包代码并返回int
        let count = labelCount()
        
        // 2.遍历创建UILabel
        for i in 0..<count{
           //labelWithIndex(index: i):先调用外部实现的闭包代码并返回UILabel
            let label = labelWithIndex(index: i)
            sc.addSubview(label)
            sc.contentSize = CGSize(width: CGFloat(count) * label.bounds.width, height: 44)
        }
        return sc
    }
  • 自定义构造方法
//新建一个对象类
class Chongzone: NSObject {
    
    var name: String?
    var age: Int = 0

    /**
     * Swift要求属性必须初始化,若定义属性(“对象类型”)没初始化,则需在后面加上 ?,若是“基本数据类型”,初始化最好直接赋值为0,因为super.init()不会分配其存储空间
     * 若在构造方法中对属性初始化,则不再需要 ?
     * 若要初始化必须重写init方法, 重写init方法后就不用加?号了
     * Swift中支持方法名重载, 同样的方法名称只要参数/返回值不同就可以
     * 若是自定义了init方法, 但没重写init方法, 默认init方法就会失效
     */
     
    //默认init方法
    override init() {
        name = "chongzone"
        age = 26
    }
    
    //自定义的构造方法
    init(name:String, age:Int) {
        self.name = name
        self.age = age
    }
    
    init(dict: [String: NSObject]) {
        // 使用kvc给self赋值之前, 必须调用super.init(分配其内存空间)
        super.init()
        self.setValuesForKeysWithDictionary(dict)
    }
}


//对应控制器调用
override func viewDidLoad() {
        super.viewDidLoad()
        // 不需import来导入某个类/控制器可直接使用, 因为Swift中有一个命名空间(namespace(默认情况下项目名称))的概念,同一个项目所有的资源共享
        // 使用Swift最好使用cocoapods管理三方框架, 避免命名空间相同导致的冲突
        
        //则对应的三种初始化方法
        let cz = Chongzone()
        print("\(cz.name), \(cz.age)")
        
        let cz2 = Chongzone(name: "chongzone", age: 26)
        print("\(cz2.name), \(cz2.age)")
        
        let cz3 = Chongzone(dict: ["name": "chongzone", "age": 26])
        print("\(cz3.name), \(cz3.age)")
    }
  • 懒加载(lazy)本质上是定义并执行一个闭包
// lazy var  变量:类型 = { ... }()
lazy var dataList: [String] = {
        print("...")
        return ["chongzone", "kongjian", "jianshu"]
    }()
  • getter、setter方法
class Chongzone: NSObject {
    var title:String? {
        didSet{
           title = title! + " happy"  //给属性设置完值之后调用, 用于更新UI
        }
    }
    
    /**
    *  如果只重写了get,没有set. 那么属性是一个"计算型"属性
    *  计算型属性不占用存储空间, 相当于OC中的readOnly 最后的 ?不需写
    */
    var name2:String{
        return "chongzone"
    }
    
    //给某个变量赋值之后,去做些额外操作,赋值length - tomeStr改变
    var length: Int? {
    didSet {
        timeStr = String(format: "%02d:%02d:%02d", arguments:  [length! / 3600, (length! % 3600) / 60, length! % 60])
          }
      }
    var timeStr: String?

    // 以下开发中几乎不用
    var _name:String?
    var name:String?{
        get{
            return _name
        }
        set{
           _name = newValue //只要外界给name赋值,则会保存在newValue
        }
    }
}

//对应的控制器
override func viewDidLoad() {
        super.viewDidLoad()
        let cz  = Chongzone()
        print(cz.name2) //chongzone
        
        cz.title = " hello" //赋值后调用 didSet
        print(cz.title!) //hello happy 
    }
  • 部分代码
//设置跟控制器,和OC同
window = UIWindow(frame: UIScreen.mainScreen().bounds)
        window?.backgroundColor = UIColor.whiteColor()
        window?.rootViewController = ViewController()
        window?.makeKeyAndVisible()

//按钮触发方法 action - 字符串""
 btn.addTarget(self, action: "btnClick:", forControlEvents: UIControlEvents.TouchUpInside)

//对应的方法
func btnClick(btn: UIButton) {
        print(__FUNCTION__)
    }
  • 析构函数
deinit {  //类似dealloc
    print("...")
}
  • 最后附上一段Swift环境下UITableView的简单实现
//核心代码
class ViewController: UIViewController {

    override func loadView() {
        let tableView = UITableView(frame: UIScreen.mainScreen().bounds)
        tableView.dataSource = self
        tableView.delegate = self
        view = tableView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    lazy var dataList : [String] = {
        return ["1","2","3"]
        }()
}

//MARK: - UITableViewDataSource
//Swift遵守协议 直接在后面添加 ,
//官方建议 数据源、代理单独写在一个扩展(extension)
extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataList.count;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        var cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier")
        if cell == nil {
            cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cellIdentifier")
        }

        cell?.textLabel?.text = dataList[indexPath.row]

        return  cell!
    }
}

终于完了… 有什么不对的地方还望指正咯,这个点…该吃饭啦。。。

    原文作者:chongzone
    原文地址: https://www.jianshu.com/p/8ebdb8c73196
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞