Swift (Learning): From Objective-C to Swift

MARK、TODO、FIXME

  •  // MARK: Similar to #pragma mark in OC
  • // MARK: - similar to #pragma mark in OC - 
  • //TODO: used to mark unfinished tasks
  • // FIXME: used to mark issues to be fixed
  • #warning: Used to mark unfinished tasks or tasks that need reminders

  The mark written in the code on the left, when you click on the structure bar above, it will be displayed as on the right

 The mark written in the code on the left, when you click on the structure bar above, it will be displayed as on the right

Note: The difference between MARK - and MARK is that there is a MARK - marked with a horizontal line above

#warning: Specific display in the code:


conditional compilation

  • The flag of the entire project can be set in Build Settings:

There are two ways to add flags:

1. Click Add directly in Active Compilation Conditions

2. In Other Swift Flags -D add the flag you want to add

  • Ways to use Flags


Print

log("123") //输出:main.swift_2690_TestSwift: 123

func test(){
    log("456", file: #file, line: #line, fn: #function)
}

test() //输出:main.swift_2692_test(): 456

System version detection


API Availability Notes

//iOS系统10以前的不能用Person类,10以后可以
//macOS系统10.15以前的不能用Person类,10.15以后可以
@available(iOS 10, macOS 10.15, *)
class Person {}

struct Student {
    //study_()方法已经不能用,被重新命名为study()
    @available(*, unavailable, renamed: "study")
    func study_() { }
    func study() { }
    //iOS系统11以前的不能用run方法,11以后可以
    //macOS系统10.12以前的不能用run方法,10.12以后可以
    @available(iOS, deprecated: 11)
    @available(macOS, deprecated: 10.12)
    func run() { }
}
  • More usage reference: https://docs.swift.org/swift-book/ReferenceManual/Attributes.html

Entrance of iOS program

  • There is a @UIApplicationMain tag on AppDelegate by default, which means: the compiler automatically generates the entry code (main function code), and automatically sets AppDelegate as the proxy of App
  • You can also delete @UIApplicationMain, customize the entry code: create a new main.swift file


Swift calls OC

  • Create a new bridging header file, the default format of the file name is: {targetName}-Bridging-Header.h

  • In the {targetName}-Bridging-Header.h file #import what OC needs to expose to Swift

  • When we create an OC file in a Swift project, it will automatically prompt you whether to create a corresponding bridging file, and click Create Bridging Header to automatically create a corresponding bridging file

  • Swift calls OC-MYPerson.h
@interface MYPerson : NSObject

@property (nonatomic, assign) NSInteger age;
@property (nonatomic, copy) NSString *name;

- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;
+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name;

- (void)run;
+ (void)run;

- (void)eat:(NSString *)food Other:(NSString *)other;
+ (void)eat:(NSString *)food Other:(NSString *)other;


@end

int sum(int a, int b);
  • Swift calls OC-MYPerson.m
#import "MYPerson.h"

@implementation MYPerson

- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name
{
    if (self = [super init]) {
        self.age = age;
        self.name = name;
    }
    return self;
}

+ (instancetype)personWithAge:(NSInteger)age name:(NSString *)name
{
    return [[self alloc] initWithAge:age name:name];
}

+ (void)run { NSLog(@"Person +run"); }

- (void)run { NSLog(@"%zd %@ -run", _age, _name); }

+ (void)eat:(NSString *)food Other:(NSString *)other
{
    NSLog(@"person +eat %@,%@", food, other);
}
- (void)eat:(NSString *)food Other:(NSString *)other
{
    NSLog(@"%zd %@ -eat %@ %@", _age, _name, food, other);
}

@end

int sum(int a, int b) { return a + b;}
  •  Swift calls OC-Swift code
var p = MYPerson(age: 10, name: "Jack")
p?.age = 18
p?.name = "Rose"
p?.run() //18 Rose -run
p?.eat("Apple", other: "Water") //18 Rose -eat Apple Water
MYPerson.run() // Person +run
MYPerson.eat("Pizza", other: "Banana") //person +eat Pizza,Banana
print(sum(10, 20)) //30

OC calls Swift

  • Xcode has generated a header file for OC to call Swift by default. The file name format is: {targetName}-Swift.h

  • OC calls Swift - Car.swift
  1. Classes that Swift exposes to OC ultimately inherit from NSObject 
  2. Use @objc to modify members that need to be exposed to OC
  3. Use @objcMembers to modify the class: 1) It means that all members will be exposed to OC by default (including the members defined in the extension); 2) Whether the exposure is successful in the end, you also need to consider the access level of the member itself
import UIKit

@objcMembers class Car : NSObject {
    var price: Double
    var band: String
    init(price: Double, band: String) {
        self.price = price
        self.band = band
    }
    func run() { print(price, band, "run")}
    static func run() { print("Car run")}
}

extension Car {
    func test() {
        print(price, band, "test")
    }
}
  • OC calls Swift - {targetName}-Swift.h
  • Xcode will generate the corresponding OC declaration according to the Swift code and write it into {targetName}-Swift.h file
@interface Car : NSObject
@property (nonatomic) double price;
@property (nonatomic, copy) NSString * _Nonnull band;
- (nonnull instancetype)initWithPrice:(double)price band:(NSString * _Nonnull)band OBJC_DESIGNATED_INITIALIZER;
- (void)run;
+ (void)run;
- (nonnull instancetype)init SWIFT_UNAVAILABLE;
+ (nonnull instancetype)new SWIFT_DEPRECATED_MSG("-init is unavailable");
@end


@interface Car (SWIFT_EXTENSION(TestSwiftCode))
- (void)test;
@end
  • OC calls Swift - OC code
Car *c = [[Car alloc] initWithPrice:10.5 band:@"BMW"];
NSLog(@"%f, %@", c.price, c.band); //10.500000, BMW
c.band = @"Bently";
c.price = 108.5;
[c run]; //108.5 Bently run
[c test]; //108.5 Bently test
[Car run]; //Car run
  • OC calls Swift - @objc
  • You can rename the symbol names (class names, property names, function names, etc.) that Swift exposes to OC through @objc
import UIKit

@objc(MYCar)
@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)
    func test() {
        print(price, band, "test")
    }
}

 

MYCar *c = [[MYCar alloc] initWithPrice:10.5 band:@"BMW"];
NSLog(@"%f, %@", c.price, c.name); //10.500000, BMW
c.name = @"Bently";
c.price = 108.5;
[c drive]; //108.5 Bently run
[c exec]; //108.5 Bently test
[MYCar run]; //Car run

Selector

  • Selectors can still be used in Swift, use #selector(name) to define a selector 
  • Selectors must be defined by methods modified by @objcMembers or @objc
@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(_:_:)))
    }
}

1. Why does the class that swift exposes to OC finally inherit from NSObject?

Because OC calls Swift classes also need to alloc, alloc comes from NSObject, and in the end, objc_msgSend message mechanism needs to be used to call the isa pointer, which comes from NSObject. The disassembly is as follows:

2. How does Swift call the bottom layer of OC? Conversely, how does OC call the bottom layer of swift?

In pure swift, calls are made through virtual tables, and methods are called through callq, etc. Calling OC in Swift still uses the runtime mechanism, and OC calls Swift, as I said before, it also uses objc_msgSend, which uses the runtime mechanism

3. How to call Car.run() modified by @objcMembers in Swift

When calling @objcMembers class Car in Swift, you will find that you still use the swift virtual table callq method. If you really want to use the objc_msgSend mechanism, you can use the dynamic keyword before the method. The disassembly is as follows:


 

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/weixin_42433480/article/details/98387586