swift5.1. Learning - 13 From OC to Swift

Posted by nelson201 on Sun, 06 Feb 2022 21:19:51 +0100

1. MARK, TODO, FIXME

MARK: similar to the #pragma mark in OC
MARK: - similar to the #pragma mark in OC-
TODO: used to mark unfinished tasks
FIXME: used to mark the problem to be fixed

2. Conditional compilation

 // Operating system: macOS\iOS\tvOS\watchOS\Linux\Android\Windows\FreeBSD 
#if os(macOS) || os(iOS)
// CPU architecture: i386\x86_64\arm\arm64
#elseif arch(x86_64) || arch(arm64)
// swift version
#elseif swift(<5) && swift(>=3)
// simulator
#Else if targetenvironment (simulator) / / you can import a module
#elseif canImport(Foundation)
#else
#endif
 #if DEBUG
// debug mode
#else 
// release mode 

#endif

3. System version detection

 if #available(iOS 10, macOS 10.12, *) {
  // For iOS platform, it can only be executed in iOS 10 and above
  // For macOS platform, it is only executed in macOS version 10.12 and above 
  // The last * indicates execution on all other platforms
}

4. Entrance of IOS program

There is a @ UIApplicationMain tag on AppDelegate by default, which indicates
The compiler automatically generates the entry code (main function code) and automatically sets AppDelegate as the agent of APP

5.Swift calls OC

Create a new bridge connector file. The default file name format is: {targetname} - bridging header h
At {targetname} - bridging header Contents of #import "xx.h" in H file that need to be exposed to Swift
When creating an OC file, a window will pop up to prompt you to create a new bridge file.

Use in Swift@_ silgen_name modify the C function name to avoid function name conflict

// C language
int sum(int a, int b) {
return a + b; }
 // Swift
@_silgen_name("sum") func swift_sum(_ v1: Int32, _ v2: Int32) -> Int32
print(swift_sum(10, 20)) // 30
print(sum(10, 20)) // 30

6.OC calls Swift

Xcode has generated a header file for OC calling swift by default (the file content will be automatically updated according to swift code during compilation). The file name format is: {targetname} - swift h
Classes exposed to OC by Swift must inherit from NSObject
Use @ objc to decorate members that need to be exposed to OC
Using @ objcMembers to decorate the class means that by default, all members will be exposed to OC (including those defined in the extension)
Whether the final exposure is successful or not also needs to consider the access level of the members themselves

@objcMembers class Car: NSObject {
//Method properties, etc 
}

You can rename the symbolic names (class name, attribute name, function name, etc.) exposed to OC by Swift through @ objc

@objc(MJCar)
@objcMembers class Car: NSObject {
var price: Double
@objc(name)
var band: String
init(price: Double, band: String) {
        self.price = price
        self.band = band
    }
@objc(drive)
func run() { print(price, band, "run") } static func run() { print("Car run") }
}
extension Car {
    @objc(exec:v2:)
func test() { print(price, band, "test") } }

//call
MJCar *c = [[MJCar alloc] initWithPrice:10.5 band:@"BMW"]; c.name = @"Bently";
c.price = 108.5;
[c drive]; // 108.5 Bently run
[c exec:10 v2:20]; // 108.5 Bently test [MJCar run]; // Car run

Selector
You can still use selectors in swift, using #selector(name) to define a selector
It must be a method modified by @ objcMembers or @ objc to define a selector

@objcMembers class Person: NSObject {
    func test1(v1: Int) { print("test1") }
    func test2(v1: Int, v2: Int) { print("test2(v1:v2:)") }
    func test2(_ v1: Double, _ v2: Double) { print("test2(_:_:)") }
    func run() {
        perform(#selector(test1))
        perform(#selector(test1(v1:)))
        perform(#selector(test2(v1:v2:)))
        perform(#selector(test2(_:_:)))
        perform(#selector(test2 as (Double, Double) -> Void))
} }

7.KVC\KVO

Swift supports the class and listener of the condition p attribute of KVC \ KVO, which are ultimately inherited from NSObject
Modify the corresponding attribute with @ objc dynamic

class Person: NSObject {
    @objc dynamic var age: Int = 0
    var observer: Observer = Observer()
    override init() {
        super.init()
        self.addObserver(observer,
                         forKeyPath: "age",
                         options: .new,
                         context: nil)
}
deinit {
        self.removeObserver(observer,
                            forKeyPath: "age")
} }
var p = Person()
// observeValue Optional(20)
p.age = 20
// observeValue Optional(25)
p.setValue(25, forKey: "age")
 class Observer: NSObject {
override func observeValue(forKeyPath keyPath: String?,
                               of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                               context: UnsafeMutableRawPointer?) {
print("observeValue", change?[.newKey] as Any) }
}

8. Associated object

In Swift, class can still use associated objects
By default, extension cannot add storage attributes
With the help of associated objects, you can achieve the effect similar to adding storage attributes for extension class

class Person {}
extension Person {
private static var AGE_KEY: Void? var age: Int {
  get {
  (objc_getAssociatedObject(self, &Self.AGE_KEY) as? Int) ?? 0
  } set {
  objc_setAssociatedObject(self, &Self.AGE_KEY,
   } }
}
newValue, .OBJC_ASSOCIATION_ASSIGN)
var p = Person()
print(p.age) // 0
p.age = 10
print(p.age) // 10

9. Multi thread locking

 private static var lock = NSLock()
static func set(_ key: String, _ value: Any) {
  lock.lock()
    defer { lock.unlock() }
}

Topics: Swift iOS