1,最明显的区别:OC一个类由.h和.m两个文件组成,而swift只有.swift一个文件,所以整体的文件数量比OC有一定减少。
2,不像C语言和OC语言一样都必须有一个主函数main()作为程序的入口,swift程序从第一句开始向下顺序执行,一直到最后。(swift将全局范围内的首句可执行代码作为程序入口,swift也有main函数,只是不用我们自己编写。)
3,swift数据类型都会自动判断,只区分变量var和常量let。
4,关于BOOL类型更加严格,swift不再是OC的非0就是真,而是true才是真false才是假。
5,swift的switch语句后面可以跟各种数据类型了,如Int,字符串,元组,区间都行,并且里面不用写break。
6,swift 中可以定义不继承于其它类的类,称之为基类(base calss)。
7,final关键字
使用final关键字修饰的类,不能被其他类继承。
继承final修饰的类会报错:Inheritance from a final class ‘……’
Swift比Objective-C优势1,Swift容易阅读,语法和文件结构简易化。
2,Swift更易于维护,文件分离后结构更清晰。
3,Swift更加安全,它是类型安全的语言:
Swift 是一个类型安全(type safe)的语言。类型安全的语言可以让你清楚地知道代码要处理的值的类型。如果你的代码需要一个 String ,你绝对不可能不小心传进去一个 Int 。
由于 Swift 是类型安全的,所以它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记 为错误。这可以让你在开发的时候尽早发现并修复错误。
当你要处理不同类型的值时,类型检查可以帮你避免错误。然而,这并不是说你每次声明常量和变量的时候都需 要显式指定类型。如果你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。有了类型推断,编译器可以在编译代码的时候自动推断出表达式的类型。原理很简单,只要检查你赋的值即可。
因为有类型推断,和 C 或者 Objective-C 比起来 Swift 很少需要声明类型。常量和变量虽然需要明确类型,但 是大部分工作并不需要你自己来完成。
4,Swift代码更少,简洁的语法,可以省去大量冗余代码。
5,Swift速度更快,运算性能更高。
swift独有1、范围运算符
a…b 表示 [a,b] 包括a和b 。 (如3…5 就是范围取3,4,5)
a… 常见的如for循环:for i in 0…9{}
2、独有的元组类型
元组(tuples)把多个值组合成一个复合值。元组内的值可以使任意类型,并不要求是相同类型。eg:
var value = (Int,String) = (x:15,y:“abc”) 复制代码
3、swift中使用let定义常量,var定义变量
使用常量,更加安全,不能够被修改,在需要对对象进行修改的时候 只能用var修饰.
4、if let 、 guard let 的用法
缩减代码量,安全处理数据逻辑。
由于很多常用的第三方框架还是oc版本,没有swift版本,但是项目里可能需要调用那些框架的功能,所以swift语言的工程还需要用到oc版本的三方,或者公司项目需要用到swift和oc混合开发时,就涉及到了Swift调用OC或者OC调用Swift
1、手动新建一个桥接头文件,文件名格式默认为:{targetName}-Bridging-Header.h,然后在Build Settings设置路径,如下
2、或者在swift工程里新建一个oc的文件时会自动d出d框询问是否自动创建桥接文件,如下
想用oc的哪些头文件,在桥接头文件中导入头文件即可,例#import “Person.h”,则在swift工程中,Person类就暴漏给swift使用了
Person.h
#import
NS_ASSUME_NONNULL_BEGIN
int sum(int a,int b);
@interface Person : 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
NS_ASSUME_NONNULL_END
Person.m
#import "Person.h"
@implementation Person
- (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文件中Swift代码
let p = Person(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
Person.run() //Person + run
Person.eat("Pizza", other: "Banana")//Person + eat Pizza Banana
print(sum(10, 20)) //30
OC调用Swift
1、Xcode已经默认生成一个用于OC调用Swift的头文件,文件名格式是:{targetName}-Swift.h
这里需要注意的是:工程名如果带有中划线-时,buildsettings的路径变成了下划线_,import引用时,写下划线的文件名即可;工程名如果带有下划线_时,buildsettings的路径也是下划线,引用时会报错找不到文件。文件内部放的是swift要暴露给oc的代码,那么也不是所有的swift代码都要暴露给oc,要暴漏给oc的代码要继承NSObject
2、Swift暴露给OC的类最终继承自NSObject(原因:因为oc有runtime,runtime是要求类有isa指针,isa指针肯定是继承NSObject才有的,所以最终要继承NSObject)
3、使用@objc修饰需要暴露给OC的成员
4、使用@objcMembers修饰类
代表默认所有成员都会暴露给oc(包括扩展中定义的成员)最终是否成功暴露,还需要考虑成员自身的访问级别例子如下:
swift文件:
class Car: NSObject {
var price:Double
var band:String
@objc 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{
@objc func test(){
print(price,band,"test")
}
}
OC文件:
Car *car = [[Car alloc] initWithPrice:1.55 band:@"bannana"];
[car run]; // 报错:No visible @interface for 'Car' declares the selector 'run'
[Car run]; //报错:No known class method for selector 'run'
[car test];
被@objc修饰的属性或者方法才能被调用
也可写成如下:
swift文件:
@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文件:
Car *car = [[Car alloc] initWithPrice:1.55 band:@"bannana"];
[car run];
[Car run];
[car test];
5、Xcode会根据Swift代码生成对应的OC声明,写入 {targetName}-Swift.h文件
6、可以通过@objc重命名Swift暴露给OC的符号名(类名、属性名、函数名等)
swift文件:
@objc(XXCar)
@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")
}
}
OC文件:
XXCar *car = [[XXCar alloc] initWithPrice:1.55 band:@"bannana"];
car.name = @"banban";
[car drive];
[car exec];
[XXCar run];
Swift 选择器(selector)
1、Swift中依然可以使用选择器,使用#selector(name)定义一个选择器
2、必须是被@objcMembers或@objc修饰的方法才可以定义选择器。
selector(选择器)是依赖于runtime的,oc里才有runtime,纯swift里是不存在runtime的
@objcMembers class XXPerson: 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))
}
}
p.run()底层是怎么调用的?
oc文件:
Person.h
#import
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
@property (nonatomic,assign) NSInteger age;
@property (nonatomic,copy) NSString *name;
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name;
- (void)run;
@end
Person.m
#import "Person.h"
#import "ludan-Swift.h"
@implementation Person
- (instancetype)initWithAge:(NSInteger)age name:(NSString *)name{
if (self = [super init]) {
self.age = age;
self.name = name;
}
return self;
}
- (void)run{NSLog(@"%zd %@-run",_age,_name);}
@end
swift文件:
var p:Person = Person(age: 10, name: "jack")
p.run()
从汇编来看,走runtime的机制,objc_msgSend
反过来,OC调用Swift底层又是如何调用?
swift写的类继承自NSObject类,暴漏给OC调用,同样走runtime那套机制,objc_msgSend
car.run()底层是怎么调用的?
第一种情况:
@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")
}
}
var car:Car = Car(price: 10.5, band: "Audi")
car.run()
在swift文件里边调用,没有走oc的runtime机制,如果想要走objc_msgSend,则在run方法前边加上dynamic关键字修饰
第二种情况(不继承自NSObject,并且没有@objcMembers修饰):
class Car{
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")
}
}
var car:Car = Car(price: 10.5, band: "Audi")
car.run()
纯swift类方法调用是走虚表v-Table那一套机制
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)