Osheep

时光不回头,当下最重要。

[Swift Tips 读书笔记]从 Objective-C 到 Swift(六)

  1. delegate
  2. Associated Object
  3. Lock
  4. Toll-Free Bridging 和 Unmanaged

delegate

OC中使用delegate时候,我们用weak修饰。一是在这个delegate实际的对象被释放时,会被重置为nil。另一个是,能够避免因为delegate不存在时候访问导致的崩溃问题。

swift中,由于protocol可以被struct enum等非class类型继承,如果设置delegate时候使用weak修饰。则该protocol只能被class继承,声明的时候需要加上关键字@objc,或者class,指明这个协议只能被class继承。

@objc protocol MyProtocol {
  func saySomething()
}
protocol MyProtocolNew : class {
  func doSomething()
}

Associated Object

// 一: OC中通过runtime绑定类型给category添加属性
@implementation Student (Category)
static char *mySchool = "mySchool";
- (void)setSchool:(NSString *)school {
    objc_setAssociatedObject(self, mySchool, school, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)school {
    return objc_getAssociatedObject(self, mySchool);
}
@end



// 二 : swift
import ObjectiveC.runtime

//Fish 类
class Fish: NSObject {

}

//添加属性
var key : Void?
extension Fish {
    var breed : String? {
        set {
            objc_setAssociatedObject(self, &key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        get {
            return objc_getAssociatedObject(self, &key) as! String?
        }
    }
}

Lock

多线程编程中,为了安全的访问同一个资源。OC中通常用@synchronized修饰一个变量。它实质上是调用了objc_sync中的objc_sync_enterobjc_sync_exit方法,并且加入了一些异常判断。所以虽然swift中已经没有了@synchronized,我们可以直接调用方法objc_sync_enter & objc_sync_exit

    let obj = String()
    objc_sync_enter(obj)
    //do something
    objc_sync_exit(obj)

    //可以自己写个全局的方法,就能直接像OC一样调用方法了
     func synchronized(_ lock: AnyObject, closure: () -> ()) {
          objc_sync_enter(lock)
          closure()
          objc_sync_exit(lock)
      }

Toll-Free Bridging 和 Unmanaged

swift对Core Foundation框架的内存管理进行了一些列的简化,降低了使用CF框架的难度。

  • 对Cocoa中的Toll-Free Foundation的处理。Cocoa中大部分NS开头的类在CF中都有对应的存在。在OC中ARC负责的只是NSObject的自动引用计数,因此对于CF对象无法进行内存管理。把对象在NS和CF之间转换的时候,需要向编译器说明是否转移内存的管理权。对于不涉及内存管理的转换情况,在转换的时候加上__bridge说明,表示内存管理权不变。

        NSURL *fileURL = [NSURL URLWithString:@"SomeURL"];
        SystemSoundID theSoundID;
        OSStatus error = AudioServicesCreateSystemSoundID(
                                        (__bridge CFURLRef)fileURL,
                                        &theSoundID);

swfit中,这样的转换,可以省略__bridge

      import AudioToolbox
      let fileURL = NSURL(string: "SomeURL")
      var theSoundID: SystemSoundID = 0
      AudioServicesCreateSystemSoundID(fileURL!, &theSoundID)
  • OC中,不能处理CF类型的创建和释放。对于CF的API,如果名字中含有Create Copy Retain,使用完成后,需要我们调用CFRealease是释放。但是在Swift中,不用显式的释放带有这些关键字的内容了。就是说Swift时代,CF也纳入了ARC的管理阵营。原理就是在合适的地方,系统自己给加上了CF_RETURNS_RETAINEDCF_RETURNS_NOT_RETAINED这样的标注。

但是有⼀点例外,那就是对于⾮系统的 CF API (⽐如你⾃⼰写的或者是第三⽅的),因为并没有强制机制要求它们⼀定遵照 Cocoa 的命名规范,所以贸然进⾏⾃动内存管理是不可⾏的。如果你没有明确地使⽤上⾯的标注来指明内存管理的⽅式的话,将这些返回 CF 对象的 API 导⼊ Swift 时,它们的类型会被对对应为 Unmanaged<T> 。

点赞