天天看点

Swift学习总结【持续更新】

1、 try、try?、try!的区别:
  • try:需要用catch捕捉异常,如:
do {
         let data = try encoder.encode(item)		
         try data.write(to: dataFilePath(), options: .atomic)
     } catch {
         print("Error encoding item array:\(error.localizedDescription)")
     }
           
  • try? :返回一个可选值类型,如果出现异常,返回nil.如果没有异常,则返回可选值。(如果不想处理异常那么可以用这个关键字),如:
let data = try? encoder.encode(item)
try? data!.write(to: dataFilePath(), options: .atomic)
           

(因为使用try?所以data为可选类型,使用前需unwrap)

  • try! : 抛出了异常后,程序会立刻停止(如果不想处理异常,而且不想让异常继续传播下去,类似NSAssert().), 如:
let data = try! encoder.encode(item)
try! data.write(to: dataFilePath(), options: .atomic)
           
2、 PropertyListEncoder、NSKeyedArchiver、NSUserDefault
  • PropertyListEncoder

    使用 PropertyListEncoder可以对遵循Codable协议的类进行归档

    将包含自定义类HighScoreItem的数组进行归档:

static func saveHighScore(_ item:[HighScoreItem]){
    let encoder = PropertyListEncoder()
    do {
        let data = try encoder.encode(item)
        try data.write(to: dataFilePath(), options: .atomic)
    } catch {
        print("Error encoding item array:\(error.localizedDescription)")
    }
}
           

解档:

static func loadHighScores() -> [HighScoreItem]{
    var items = [HighScoreItem]()
    let path = dataFilePath()
    if let data = try? Data(contentsOf: path){
        let decoder = PropertyListDecoder()
        do{
            items = try decoder.decode([HighScoreItem].self, from: data)
        }catch{
            print("Error decoding item array:\(error .localizedDescription)")
        }
    }
    return items
}
           
  • NSKeyedArchiver

    NSKeyedArchiver可以将遵守NSCoding协议的Cocoa类进行归档,将数据转换为 Data 类型,然后再存储到UserDefaults或写到文件:

do {
    let data = try NSKeyedArchiver.archivedData(withRootObject: item, requiringSecureCoding: true)
    try data.write(to: dataFilePath(), options: .atomic)
} catch  {
    print("Error encoding item array:\(error.localizedDescription)")
}
           
  • NSUserDefault

    适合存储数据量较少的数据

let defaults = UserDefaults.standard
defaults.set(item, forKey: "item");
           
3、NSArry和Array

Array是Swift中的结构体类型(struct), 属于是值类型.

NSArray是OC中的对象类型, 属于引用类型.

var aarr = ["happy", "every", "day"]
    var barr : NSMutableArray = ["happy", "every", "day"]
    
    //1
    aarr[2] = "minute" //直接改变了aarr第二个元素的值
    barr[2] = "minute" //让barr第二个元素指向"minute"
    print("1---\(aarr)")
    print("1---\(barr)")
    /*输出:
        1---["happy", "every", "minute"]
        1---(
        happy,
        every,
        minute
        )
    */
    
    //2
    func changeA (var a:Array<String>) {
        a[2] = "second" //a是对aarr的拷贝
    }
    func changeB (a : NSMutableArray) {
        a[2] = "second" //a是对barr的引用
    }
    changeA(aarr) //值类型赋值时进行拷贝, 改变是a[2]的值, aarr并没有影响
    changeB(barr) //引用类型赋值时传递的是引用, a[2]和barr[2]都指向同一个地址.
    print("2---\(aarr)")
    print("2---\(barr)")
    /*输出:
        2---["happy", "every", "minute"]
        2---(
        happy,
        every,
        second
        )
    */
           

代码来自HWenj的文章《Swift中Array和OC中的NSArray》

4、weak和unowned区别
  • unowned标识的变量不能是可选类型(Optional),不能指向nil,必须在 init 方法中初始化值。
  • weak标识的变量可以为可选类型,可以指向nil。

    参考:纠结的哈士奇的文章

5、oc和swift中==的区别

如果比较的是类(引用类型)

  • 在Objective-C 中,只有两个对象指向的内存地址一样才为true
  • 在Swift中,对比的是对象的值,跟内存地址无关(如果要对比内存地址使用===)
6、方法的参数

一般方法会有一个或多个参数,每个参数会有两个名字,外部参数名(external label)和内部参数名(internal label),例如:

func downloadImage(for searchResult: SearchResult,  
                withTimeout timeout: TimeInterval, 
                  andPlaceOn button: UIButton) {
  . . .
}
           

这个方法有3个参数searchResult、timeout、button,这些是内部参数名,可以在方法内使用。

而外部参数名是方法名的一部分,即以上方法名为:downloadImage(for:withTimeout:andPlaceOn:)

调用方法时,写法为:

downloadImage(for: result, withTimeout: 10, 
                            andPlaceOn: imageButton)
           

有些方法第一个外部参数名会以下划线“_”代替,从而忽略外部参数名,如:

override func tableView(_ tableView: UITableView, 
      numberOfRowsInSection section: Int) -> Int
           

这些方法一般都是来源于过去Objective-C的写法,已经把首个外部参数名合并在方法名之中。

7、switch技巧

可以通过"…<"匹配范围。如:

switch difference {
  case 0:
    title = "Perfect!"
  case 1..<5:
    title = "You almost had it!"
  case 5..<10:
    title = "Pretty good!"
  default:
    title = "Not even close..."
}
           

8、for循环技巧

循环遍历数组时,我们这样写:

for item in items {
  if !item.checked {
    count += 1
  }
}
           

可以在后面加上条件选择

for item in items where !item.checked {
  count += 1
}
           

如果我们想要循环n次,可以这样写:

for i in 0...4 {   // or 0..<5
  print(i)
}
           

也可以通过stride方法:

for i in stride(from: 0, to: 5, by: 1) {
  print(i)
}
           

stride()方法创建了代表从0到5,增长间隔是1的对象。如果想输出从0到5的偶数,则把最后一个参数改为2,如果想要倒数,最后的参数传入负值即可。

9、通过filter筛选

如果要筛选出数组中,符合某一条件的对象。如筛选出items数组中,属性checked为false的对象,可以用filter方法

10、存储属性(Stored property)vc计算属性(Computed property)

  • 存储属性:常见的实例变量和常量
  • 计算属性:不存储数据,在读和写时会执行逻辑代码,如:
var indexOfSelectedChecklist: Int {
  get {
    return UserDefaults.standard.integer(
                forKey: "ChecklistIndex")
  }
  set {
    UserDefaults.standard.set(newValue, 
                                forKey: "ChecklistIndex")
  }
}
           

11、类中的方法

类的方法有三种:

  • 实例方法:需要先创建实例,才能调用,如:
let myInstance = MyObject()   // create the object instance
. . .
myInstance.doSomething()      // call the method”
           
  • 类方法:不需要创建实例,直接由类调用,常用做工厂方法来创建实例,如:
class MyObject {
  . . .

  class func makeObject(text: String) -> MyObject {
    let m = MyObject()
    m.text = text
    return m
  }
}

let myInstance = MyObject.makeObject(text: "Hello world")
           
  • 初始化方法:除了上面的工厂方法,也可以使用自定义的初始化方法,用于创建和初始化实例。在初始化方法中,实例变量和常量必须被赋值(Swfit要求在初始化方法执行完之后,变量和常量除非是可选类型,否则必须被赋值),如:
class MyObject {
  . . .

  init(text: String) {
    self.text = text
  }
}

let myInstance = MyObject(text: "Hello world")
           

一个类的初始化方法可以有多个,如UITableViewController有init?(coder:)、init(nibName:bundle:)、init(style:) 等多个初始化方法。

12、if判断技巧

如果我们要用if判断多个条件,在Objective-C中可以用“&”进行连接,而在Swift中可以使用“,”进行连接,如:

if error == nil, let p = placemarks, !p.isEmpty {
  self.placemark = p.last!
} else {
  self.placemark = nil
} 
           

只有error为nil、p不为nil、p数组不为空(placemarks为数组)三个条件同时为真,if判断才为真。

13、 as、as?、as!的区别:

【先下班】