Swift开发

Swift入门

2015-11-26  本文已影响492人  Jimmy_P

苹果为什么要推出Swift

Swift 特色

Swift 发展

现状

学习资源


Playground

快速体验

//: 输出hello world
print("hello world")

//: 下面来体验一下swift和OC的区别

//: 创建一个UIView
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

//: 设置背景色
view.backgroundColor = UIColor.redColor()

//: 创建一个UIButton
let button = UIButton(type: UIButtonType.ContactAdd)

//: 设置按钮中心位置
button.center = CGPoint(x: 50, y: 50)

//: button添加到view里面
view.addSubview(button)
//: 在swift中访问属性和调用方法都是通过.来进行的
  1. 语句末尾不用使用;
  2. 在 Swift 中使用print()替代 OC 中的NSLog
  3. 在swift中访问属性和调用方法都是通过点语法 . 来进行的
  4. 在 Swift 中要实例化一个对象可以使用 类名()的格式,与 OC 中的alloc/init等价
  5. OC 中的[[类名 alloc] initWithXXX], [类名 类名WithXXX]在 Swift 中通常可以使用类名(XXX: )找到对应的函数
  6. OC 中的 [UIColor redColor] 类方法,在 Swift 中通常可以使用 类名.XXX( ) 找到对应的函数

变量和常量

/*
    OC中:
       定义变量: int a = 1;
       定义常量: int const a = 1;

    swift:
      定义常量:   let 常量名 = 值
      定义变量:   var 变量名 = 值

    var 修饰的是可变的
    let 修饰的是不可变的

*/

// 定义变量
var a = 10

// 修改变量
a = 20

print("a = \(a)")

// 定义常量
let b = 10

print("b =  \(b)")

//b = 15

// 常量初始化后不能再修改

类型推导和类型装换

自动推导

重要技巧:Option + Click 可以查看变量的类型

Option + Click 可以查看变量的类型

如果要对不同类型的数据进行计算,必须要显式的转换

//: 自动推导
let a = 10

let b = 7.5

// binary operator '+' cannot be applied to operands of type 'Int' and 'Double'
// let c = a + b

// 将a转成Double类型
let c = Double(a) + b

// 将b转成Int类型
let d = a + Int(b)

// 定义一个float类型的常量, 定义时指定类型
let e: Float = 7.5

// 定义时指定类型 左右类型不匹配: 'Double' is not convertible to 'Float'
// let k: Float = c

// 先声明,后定义
var k: Int
// 在没有初始化之前不能使用, variable 'k' used before being initialized
//print(k)
k = 1

字符串 String

定义字符串

  OC的字符串:
        NSString *str = @"hello";
      格式化字符串: [NSString stringWithFormat:@"%.02f", 3.14159]

  swift中定义字符串:
      var 变量名 = "hello"

//: 定义字符串
var str = "我要飞的更高"
// swift 2.0 中遍历字符
for c in str.characters
 {
  print(c)
}
// 返回实际字符的个数
let len2 = str.characters.count

// 字符串拼接
let hello = "Hello"
let world = "World"
let z = "个赞"
let i = 32
let helloworld = hello + " " + world

//: "\()" 把其他类型转成字符串
let title = "\(i) " + z
//: 格式化字符串,保留2位小数
let pi = 3.141592653
let fmtString = String(format: "%.02f", arguments: [pi])

eg. 网络请求返回一个地址,要判断是否是gif图片


let addr1 = "wwww.baidu.com/aa/bb/aa.Gif"
let addr4 = addr1.lowercaseString
addr4.hasSuffix("gif")
let subString = (addr4 as NSString).substringWithRange(NSMakeRange(addr4.characters.count - 3, 3))
subString == "gif"

Optional可选

注意:强行解包必须要确保解包后的值不是nil,否则会报错

/*:
    定义一个电话号码? int num = 10086; int num = 0;经常会忽略对没有电话号码的判断

    swift推出可选类型(Optional), 表示一个变量或常量可能有值,也有可能没有值.时刻提醒我们变量可能没有值
        可选类型的定义: 类型的后面加?
*/

// 定义可选类型
let num: Int? = 10086

// Optional(10086)
print(num)

// value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
// !表示强制拆包. 需要确定可选一定有值.
let sum = num! + 10

// 定一个可选,没有赋值
var num2: Int?

// 可选没有值用nil表示
print(num2)

// 可选没有值,进行强制拆包: fatal error: unexpectedly found nil while unwrapping an Optional value
//let sum3 = num2!

// 在对可选操作的时候需要判断是否有值.
if num2 != nil {
    let sum3 = num2! + 10
    print("sum3: \(sum3)")
} else {
    print("可选没有值")
}

// 可选绑定, 当可选有值的时候,会把num2!赋值给 num3
if let num3 = num2 {
    print(num3)
} else {    // 如果num2没有值.
    print("num2没有值")
}

if条件分支

/*
    在C和OC中非0既真,0为假
        int a = 1;
        if (a)
         {
            NSLog(@"");
         }

    1. 在swift中没有非0既真、0为假,swift中Bool类型只有2个值:true 真,false 假
    2. 条件必须是Bool类型,或返回Bool类型的表达式
    3. 条件可以省略括号
    4. { }不能省略
*/
var a = 1
//: type 'Int' does not conform to protocol 'BooleanType'
//if (a) 
//{
//    print(a)
//}

let iosNB = true

if iosNB 
{
    print("ios 牛x")
}

var pass = "及格"
var fail = "不及格"

let score = 59

//: 运算符结果返回Bool
if score > 60 
{
    print(pass)
} 
else 
{
    print(fail)
}

//: 注意问号前一定要有空格, 条件也只能是Bool类型
var c = (score > 60) ? pass : fail
print(c)


循环

//OC的for:
for (int i = 0; i < 5; i++) 
{
    NSLog(i)
}
for var i = 0; i < 5; i++ 
{
    print(i)
}
// swift 常用写法
for i in 0...5
{
    print(i)
}
// 范围运算符
// ... 闭合范围运算符 表示 a 到 b, [a, b] 0-5, 包含a,也包含b
// ..< 半闭合范围运算符 表示 a 到 b, [a, b) 0-4, 包含a,但是不包含b
for _ in 0...5
{
       print("hello")
}

switch

判断学生分数

/*:
    判断分数:
        90-99: 优秀
        80-89: 良好
        70-79: 中等
        60-69: 及格
        60以下: 不及格
*/

let score = 99

// swift的 swith执行完一个case后默认不会执行下一个case
switch (score / 10) 
{
    case 9 :
        print("优秀")
    case 8 :
        print("良")
    case 7 :
        print("中")
    case 6 :
        print("及格")
    default:
        print("不及格")
}  

如果要执行下一个case需要用fallthrough关键字

switch (score / 10) 
{
    case 9 :
        print("优秀")
    case 8:
        print("走我了吗?")
        fallthrough
    case 7:
        print("良")
    case 6 :
        print("及格")
    default:
        print("不及格")
}

switch通过区间运算符匹配

//: switch通过区间运算符匹配
switch (score) 
{
    case 90...100 :
        print("优秀")
    case 70..<90 :
        print("良好")
    case 60..<70 :
        print("及格")
    default:
        print("不及格")
}

匹配字符串

/*
Monday 星期一
Tuesday 星期二
Wednesday 星期三
Thursday 星期四
Friday 星期五
Saturday 星期六
Sunday 星期日
*/

//: 可以匹配字符串
let weekDay = "Tuesday"
switch weekDay 
{
    case "Monday":
        print("星期一,该上班了")
    case "Friday":
        print("星期五,明天不上班")
    default:
        print("忙的忘记星期几了")
}

数组

/*:
  OC中定义数组:
      NSArray *arr = @[元素1, 元素1, 元素1];

  在swift中定义数组:
      var 数组名 = [元素1, 元素2, ...]
*/
//: swift定义数组
var array = ["bmw", "benz", "byd"]
var array1 = [3, 5, 7, 3, 2] // 类型是[Int],表示Int类型的数组,数组里面的元素都是Int类型
var array2 = ["liudehua", 54]  // 类型是[NSObject],数组里面的元素都是NSObject类型,用的很少
var array3: [Int] = []
var array4 = [Int]()
定义数组时指定数组类型
var array5: [Int] = [5, 6]
//: 遍历数组中的所有元素
for var i = 0; i < array1.count; i++ {
  let n = array1[i]    //取出数组中的某个元素
  print(n)
}
//: 遍历数组中的所有元素
for n in array1 {
  print("i = \(n)")
}
print(array[0])
print(array[1])

数组的常用操作

//: 取钱
var persons = ["liudehua", "zhangxueyou", "guofucheng"]

//: 添加元素到数组末尾
persons.append("liming")

//: 向数组中指定位置插入一个元素
persons.insert("chenglong", atIndex: 0)

//: 修改数组中元素的值
persons[0] = "fangzuming"
persons

//: 获取数组个数
persons.count

//: 删除数组最后位置的元素
persons.removeLast()
persons

//: 删除数组中指定位置的元素
persons.removeAtIndex(2)
persons

//: 删除数组中的所有元素
persons.removeAll()

// 判断数组是否为空
persons.isEmpty

/*
    let修饰的数组是不可变数组或者说常量数组
    var修饰的数组是可变数组
*/
let arr7 = [1, 2, 3]
//arr7[0] = 1
//arr7.removeAll()
//arr7.append(1)

// 数组合并
var arr8 = [1]
var arr9 = [2, 3, 5]

arr9 += arr8
print(arr9)

//: 数组不能越界访问,Array index out of range
//arr9[20]

元组


//: 刘德华花5万美元买了一辆白色的宝马轿车
//: 定义元组类型为 (String, Int, String, String)
let car = ("liudehua", 50000, "white", "bmw")
//:访问元组中的元素
car.0
car.1
//: 定义元组时,指定元素名称
var car2 = (name: "liudehua", price: 50000, brand: "bmw", color: "white")
//: 元组通过元素名称访问
car2.price
car2.brand
car2.brand = "byd"
//: 元组的分解(值绑定)
let name1 = car1.name
let price1 = car1.price
let color1 = car1.color
let brand1 = car1.brand
//
let (name2, price2, color2, brand2) = car1
name2
brand2
//
let (name3, price3, color3, _) = car1
name3

字典


/*
    OC定义字典:
        NSDictionary *dict = @{key1: value1, key2: value2, ...};

    swift定义字典:
        var 数组名 = [key1: value1, key2: value2, ...]

    let 不可变
    var 可变
*/

//: 定义字典
var dict1 = ["name": "liudehua", "age": 54]    //[String : NSObject]
var dict2 = ["name": "liudehua", "nickName": "huazai"]   //: [String : String]
var dict4 = [NSString: Int]()
var dict5: [NSString: Int] = [:]
//: 遍历字典的所有key
for n in dict1.keys {
  print(n)
//    print(dict1[n])
}
//: 遍历字典所有value
for k in dict1.values {
  print("k === \(k)")
}
//: 遍历字典
for n in dict6 {
//    print(n)
//    print(n.0)
//    print(n.1)
}
//: 开发中用的最多的遍历字典的方式
//: k, v 可以随便写,前面是 key,后面是 value
for (k, v) in dict1 {
  print(k + "--- \(v)")
}
//: 跳过不关心的值
for (_, v) in dict1 {
  print("对key不关心--- \(v)")
}

字典常用操作

var dict7 = ["name": "liudehua", "age": 53]
//: 访问字典中的元素
dict7["name"]

//: 当字典的key存在时,修改字典中的元素
dict7["age"] = 54
dict7

//: 当字典的key不存在时,会新增key和value
dict7["title"] = "king"
dict7

//: 删除字典中指定的key和对应的value
var dict8 = ["name": "liudehua", "age": 54, "height": 1.74]
dict8.removeValueForKey("age")
dict8

//: let修饰的字典不能改变 cannot assign through subscript: 'dict9' is a 'let' constant
let dict9 = ["name": "liudehua", "age": 54, "height": 1.74]
//dict9["name"] = "lisi"

枚举


/*:
  OC 枚举:
      enum Season {
          Spring,
          Summer,
          Autumn,
          Winter
      };

      //: 定义枚举变量
      enum Season season = Spring;
*/
//: 定义枚举类型,枚举的每个成员前面加case
enum Season {
  case Spring
  case Summer
  case Autumn
  case Winter
}
//: 定义一个枚举变量
var season = Season.Spring
//: 再次修改值的时候可以直接 .成员, 是因为类型推导.
season = Season.Summer
season = .Summer
print(season)

switch判断枚举类型

//: switch判断枚举类型
switch season {
case Season.Spring:
    print("春天")
case Season.Summer:
    print("夏天")
case Season.Autumn:
    print("秋天")
case Season.Winter:
    print("冬天")
}

//: 可以省略枚举名
var season2 = Season.Spring
switch season2 {
case .Spring:
    print("春天")
case .Summer:
    print("夏天")
case .Autumn:
    print("秋天")
case .Winter:
    print("冬天")
}

枚举成员类型

//: 定义枚举,成员类型为Int
enum Direction: Int {
    case North = 0
    case South = 1
    case East = 2
    case West = 3
}

//var direction = Direction.North

//: 使用初始值来定义枚举变量
var direction = Direction(rawValue: 1)
print(direction)

//: 可选绑定
if let dir = direction {
    switch dir {
    case .North:
        print("北")
    case .South:
        print("南")
    case .East:
        print("东")
    case .West:
        print("西")
    }
}

函数


func 函数名(形参名1: 形参类型1, 形参名2: 形参类型2, ...) `->` 返回值 {
  // 代码实现
}
/*函数如果没有返回值:
      1. 省略
      2. -> Void
      3. -> ()

  外部参数名,作用能够方便调用人员更好地理解函数的语义
  带外部参数名的参数列表格式:
      (外部参数名1 形式参数名1: 参数类型1, 外部参数名2 形式参数名2: 参数类型2, ...)*/
//: 定义函数
func sum(a: Int, b: Int) -> Int {
  return a + b
}
//: 调用函数, b表示外部参数名
sum(10, b: 20)
//: 没有返回值
func sayHello() -> () {
  print("hello")
}
sayHello()
//: 为什么有外部参数名呢?
func addStudent(name: String, age: Int, number: Int) {
    print("name = \(name), age = \(age), number = \(number)")
}

//: 如果没有外部参数名,我们很难判断每个参数的作用
//addStudent("liudehua", 54, 53)

//: 有外部参数名,每个参数的作用一目了然,swift2.0默认帮我们生成除第一个参数外的所有外部参数名
addStudent("liudehua", age: 54, number: 53)

//: 指定外部参数名
func addStudent2(stu_name name: String, stu_age age: Int, stu_number number: Int) {
    print("name = \(name), age = \(age), number = \(number)")
}

addStudent2(stu_name: "liudehua", stu_age: 54, stu_number: 53)
/*:
在c语言中要返回多个值:
  1.传参数时传入指针,在函数内部修改该指针指向的值
  2.返回一个结构体
  3.返回数组
*/
//: 在swift中可以通过返回元组来方便的返回多个值
func getStudent() -> (String, Int, Int) {
  return ("liudehua", 54, 53)
}
//: student是一个(String, Int, Int)的元组
let student = getStudent()
//: 可以通过.0 .1 来访问
student.0
student.1
//: 函数通过元组返回多个值,并且为元组中的元素取名成,方便调用
func getStudent2() -> (name: String, age: Int, num: Int) {
  return ("liudehua", 54, 53)
}
let student2 = getStudent2()
student2.name
student2.age

闭包


定义

//: () -> Void 表示一个 `不需要参数,返回值为空` 的闭包类型
UIView.animateWithDuration(0) { () -> Void in
//
}
  { (形参名称1: 形参类型1, 形参名称2: 形参类型2, ...) -> 返回值 `in`
          //要执行的代码
  }
// 定义闭包
var closure = { (text: String) -> Void in
}
// 调用闭包
closure("学习闭包")

闭包使用场景(回调)

  // 闭包的使用场景: 回调
  // 在子线程执行完任务后通知调用者
  func loadData(finished: (result: String) -> Void) {
      dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
          print("拼命加载数据: \(NSThread.currentThread())")

          dispatch_async(dispatch_get_main_queue(), { () -> Void in
              print(": \(NSThread.currentThread())")
              // 通知调用者
              finished(result: "获取到20条数据")
          })
      }
  }
loadData { (result) -> Void in
  print("网络请求完成: \(result)")
}

闭包的简写

// 当闭包的参数和返回都为空时可以省略 () -> Void in
UIView.animateWithDuration(1) {
}

// 闭包是最后一个参数,可以把闭包放在()后面,尾随闭包
UIView.animateWithDuration(1) { () -> Void in
}

类的定义


在OC中一个类包涵.h和.m两个文件
  .h:
      @interface 类名: 父类名
      @end

  .m:
      @implement 类名
      @end

  实例化类:
      类名 *变量名 = [[类名 alloc] init];
class 类名: 父类名 {
      //: 一些属性
      //: 一些方法
  }

  实例化一个类:
  var 变量名 = 类名()

注意:
  1swift的继承和oc一样是通过:, swift也只有单继承
  2.访问类的属性和调用类的方法都是通过.来进行的
  3.覆盖父类方法, 需要加关键字 override

//: 定义一个类, 没有继承任何类的类,称之为 基类,超类
class Person: NSObject {
  // 名称属性
  var name = "liudehua"
  // 年龄
  var age = 54
  // 身高
  var height = 1.78
  // 体重
  var weight = 70.0
  // 方法
  func sleep() {
      print("累了,睡觉")
  }
  func eat() {
      print("饿了,吃饭")
  }
}
// 实例化类Person
var p = Person()
// 访问属性
print(p.name)
// 修改属性
p.name = "zhangsan"
print("名称修改后:\(p.name)")
// 调用方法
p.sleep()
//: 继承 和OC 一样通过 : 来实现继承
class Student: Person {
  // 班级属性
  var grade = "ios05期"

  // 定义学习方法
  func study() {
      print("开开心心学习,高薪就业")
  }

  // 覆盖父类方法, 需要加关键字 override
  override func sleep() {
      print("学习累了,睡觉")
  }
}
// 实例化Student
let s = Student()
print(s.grade)
// 调用Student的sleep
s.sleep()

类的属性


1.在.h声明gettersetter方法
2.在.m实现gettersetter 方法
3.在.m生成 _成员变量

willSet: 在属性将要发生改变时调用
didSet: 在属性已经发生改变时调用

  @interface Person ()

  @property (nonatomic, assign) CGFloat heightCM;

  @end

  @implementation Person

  // getter
  - (CGFloat)heightCM {
      return ;
  }

  // setter
  - (void)setHeightCM:(CGFloat)heightCM {
      // 没有 _heightCM = heightCM
  }
class Person {
  //: 存储型属性
  var name = "liudehua"
//
  //: 存储型属性,单位是m
  var height = 1.74
//
  //: 计算型属性
  var heightCM: Double {
      get {
          return height * 100
      }

      set {
          height = newValue / 100
      }
  }
//
  //: 存储型属性
  var age = 54
//
  //: 存储型属性
  var weight: Float = 70 {
      willSet {
          print("weight willSet")
      }

      didSet {
          print("weight didSet")
      }
  }
//
  //: 定义一个sleep方法
  func sleep() {
      print("person 累了, sleep...")
  }
//
  //: 定义一个eat方法
  func eat() {
      print("person 饿了, eat...")
  }
}
// 实例化Person
var person = Person()
person.height
person.heightCM = 178
person.height
person.weight = 72
var person2 = Person()
//: person的weight属性和person2的weight没有关系,相互独立的.
person2.weight = 60
print(person2.weight)

类属性

//: 定义圆
class Circle {
  //: 只要是圆就有圆周率,圆周率的值固定不变,不管创建多少个实例,都共享这个圆周率属性
  //: 类型属性: 只读计算型属性
  class var pi: Double {
      return 3.141592653
  }
//
  var radius = 20.0
//
  //: 周长,只读计算型属性
  var perimeter: Double {
      return 2 * Circle.pi * radius
  }
}
//
//Circle.pi = 1
//
var pingpong = Circle()
pingpong.perimeter
//
pingpong.radius = 40
pingpong.perimeter

构造函数


自定义Car对象

class Person {
    var name: String
}
class Person {
  // 直接赋值
  var name: String = "liudehua"
}
// 实例化
var p1 = Person()
p1.name
// 实例化
var p2 = Person()
p2.name
//: 实例化出来对象 name属性都一样,显然不合理.
class Person {
  var name: String?
}
var p = Person()
p.name = "liudehua"
print(p.name)
//: 用可选的,打印出来都带Optional

利用 init 函数为属性初始化

`

class Person: NSObject {
   var name: String

    var age: Int

    //: 重写父类构造函数
    override init() {
        print("init")
        name = "liudehua"
        age = 22
    }
}

重载构造函数

//: 重载构造函数
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }

子类构造函数


class Stuent: Person {
    var grade: String

    // 子类构造函数需要调用父类构造函数
    // 需要先初始化子类属性,在调用父类构造函数
    init(name: String, age: Int, grade: String) {
        self.grade = grade
        super.init(name: name, age: age)
    }
}

convenience 构造函数

便利构造函数: 它是辅助性的构造函数.方便创建对象

    /// 方便创建ios05期学生
    convenience init?(stuName: String, stuAge: Int) {

        // 判断age是否合法
        if stuAge < 0 || stuAge > 130 {
            print("年龄不合法")
            return nil
        }

        self.init(name: stuName, age: stuAge, grade: "ios05期")
    }

构造函数小结

  1. 不需要func关键字.名称是固定的,都叫 init
  2. 当类没有实现构造函数时,系统会添加一个默认的构造函数.
  3. 如果实现了构造函数,系统就不会添加默认构造函数
  4. 如果子类没有实现构造函数.会继承父类的构造函数
  5. 子类构造函数需要调用父类构造函数
  6. 需要先初始化子类属性,在调用父类构造函数
  7. 子类一旦实现了构造函数.就不会继承父类的构造函数

懒加载

在 iOS 开发中,懒加载是无处不在的

lazy var p = Person()
// 方法2, 需要指定p的类型
lazy var p: Person = {
  let person = Person()
  return person
}()
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
  p.name = "lisi"
  print("p.name: \(p.name)")
}
class Person: NSObject {
  var name: String?

  override init() {
      print("初始化")
  }
}
上一篇 下一篇

猜你喜欢

热点阅读