OC,swift,javascript,Dart语言比较

OC 是 动态类型语言&&强类型语言&&动态语言&&编译型语言
swift 是 动态类型语言&&强类型语言&&静态语言&&编译型语言
javascript是一种动态类型语言和非强类型语言,与php类似
Dart 属于是强类型语⾔,var 来声明变量, Dart 会⾃推导出数据类型这一点与swift很像,但是Dart在编译期间不进⾏任何的类型检查,⽽是在运⾏期进⾏类型检查。

OC和swift混编注意点:
1.新建一个swift文件时,会提示你是否建立桥接文件,系统会建立“工程名-Bridging-Header.h”
2.配置工程Build Settings 设置Defines Module 为Yes,设置Product Module Name 为当前工程名
3.swift引用OC文件,需要在“工程名-Bridging-Header.h”桥接文件中导入OC头文件
4.OC引用swift文件,在OC文件中导入#import “工程名-Swift.h”,注意swift文件的方法名前面要加@objc,不然方法调用不了

array

flatMap: 对数组的每一个元素做一次处理,返回处理后的数组。
与map的区别是:
1.返回后的数组中不存在nil, 同时也会把Optional解包。
2.flatMap还能把多维数组变成一维数组。

compactMap与flatMap的区别上面也说了,当闭包中的返回结果是可选的时候,使用compactMap代替flatMap

as、as!、as?

as
1.从派生类转换为基类,向上转型(upcasts) 子类赋值给父类 let person1 = tom as Person
2.消除二义性,数值类型转换 消除整型还是浮点
3.switch语法检测对象的类型 case let person1 as Student:

as!
向下转型(Downcasting)时使用 父类赋值给子类

as? as? 和 as! 操作符的转换规则完全一样。但 as? 如果转换不成功的时候便会返回一个 nil 对象。

as?判断一个可选类型是否可以转换为指定类型,如果可以,系统自动转换取值,如果不可以,返回nil
if let name = dict1[“name”] as? String

as!将可选类型转为指定类型,如果不能转换,会崩溃

语法糖 ?? // 如果可选类型的name有值,则解包并使用,如果没有值,则使用?? 后面的值 let str1 = name ?? “”

swift self 使用

1.参数名和自身的属性名同名,消除访问属性,调用方法时所产生的歧义
class AClass {
var greeting: String
init(greeting: String) {
// 使用self区分属性和参数
self.greeting = greeting
}
}
2.在便利构造函数中调用自身的指定构造函数时
convenience init() {
/*必须使用self,因为按照二段构造的规则,在第一阶段初始化完成之前,无法使用self,
而且由于面向对象语言的特性,所有的初始化方法名都是init,没有self,系统不知道调用谁的init */
self.init()
}
3.闭包中访问自身属性和调用自身方法时
UIView.animateWithDuration(0.25) { () -> Void in
/闭包可能被抛出,其必须知道其中的方法和属性属于谁,所以要用self/
self.layoutIfNeeded()
}
4.被mutating修饰的值类型方法中,修改self属性时
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}

函数省略规则

func someFunction(_ firstParameterName: Int, secondParameterName: Int) {

}
someFunction(1, secondParameterName: 2)

1.将作为参数的函数变成无名函数

变化规则: 及闭包
a. 省略函数名 保留花括号 {}
b. 把参数列表和返回参数 (即函数类型) 写在{}第一行
c. 用in 将 函数类型 与 函数体 区分开来

2.省略返回类型, 当编译器已知该函数返回类型的时候

3.省略参数列表和in, 当没有参数的时候

4.省略参数类型和参数列表括号,当编译器已知参数类型的时候

5.省略 函数类型和in ,并使用$0,$1等访问参数,当编译器已知参数类型的时候

6.省略 函数类型和in ,不访问函数参数

规则: 使用下划线 _ 代替整个参数列表

// 定义函数
func test(callback:(_ str : String)->()){
callback(“test”)
}
// 方式1 调用函数:尾随闭包
test(){(js:String) in
print(js)
}
如果闭包是唯一的参数,那么()也可以省略
// 方式2
test{(js:String) in
print(js)
}

reversedNames = names.sorted(){$0>$1}
转化
reverseNams = names.sorted{$0>$1}

7.当且仅当无名函数作为caller函数的最后一个参数的时候,
可以省(即把caller函数结束标志略最后一个参数名称的 “)” 放在倒数第二个参数的末尾)
将此无名函数紧跟在 “)” 后面,作为最后一个参数

private 表示代码只能在当前作用域或者同一文件中同一类型的作用域中被使用,
fileprivate 表示代码可以在当前文件中被访问,而不做类型限定。

你可以在遵循协议的类中实现构造器,无论是作为指定构造器,还是作为便利构造器。无论哪种情况,你都必须为构造器实现标上 required

mutating
如果你在协议中定义了一个实例方法,该方法会改变遵循该协议的类型的实例,那么在定义协议时需要在方法前加 mutating 关键字。这使得结构体和枚举能够遵循此协议并满足此方法要求

属性:
1.如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使有属性被声明为变量也不行
2.除存储属性外,类、结构体和枚举可以定义计算属性。计算属性不直接存储值,而是提供一个 getter 和一个可选的 setter,来间接获取和设置其他属性或变量的值。
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
print(“get”)
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
print(“set”)
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValue。

set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}

属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。

class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print(“About to set totalSteps to (newTotalSteps)”)
}
didSet {
if totalSteps > oldValue {
print(“Added (totalSteps - oldValue) steps”)
}
}
}
}

3.只读计算属性的声明可以去掉 get 关键字和花括号:
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}

4.使用关键字 static 来定义类型属性。在为类定义计算型类型属性时,可以改用关键字 class 来支持子类对父类的实现进行重写

数组遍历
// 方式1
for s in arrayM {
print(s)
}
// 方式2
for i in 0…<arrayM.count{
print(arrayM[i])
}
// 方式3: 部分遍历
for i in arrayM[0…<2]{
print(arrayM[i])
}
// 方式4 : (同时获取下标和对应的值)
for (index ,item) in arrayM.enumerated{
print(index) // 下标索引
print(item) // 下标的对应值
}

let array4 = array1 + arrayM

字典遍历

// 遍历键
for key in dict2.keys{
print(key)
}
// 遍历值
for value in dict2.values{
print(value)
}

// 键值遍历
for (k,v) in dict2{
print(k)
print(v)
}

类和结构体的区别:

类:面向对象的编程
结构体:面向协议的编程,比面向对象的编程能高级点,结构体可以实现类的所有方法

类方法:需要初始化对象调用 引用类型(类似于OC中的指针)
结构体:可以使用对象直接调用 值类型

结构体只需要给你变量的类型
类需要给出变量的初始值

类需要自己调用初始化方法
结构体不需要自己调用初始化方法

结构体的主要区别是结构体中有个关键字mutating 可以改变结构体的内部方法
结构体改变内容时受let的影响,也就是说结构体中尽量使用var 关键字

protocol中可以声明变量,方便在协议方法中使用
协议方法的具体实现需要在extension中来实现
协议中不允许定类义方法,需改为静态方法

在 extension 后面加上约束关键字【where】,并注明该协议只能被某个类(包括子类)所遵守,而且此时我们还可以拿到遵守该协议的控制器的view

1、private
private访问级别所修饰的属性或者方法只能在当前类里访问。

2、fileprivate
fileprivate访问级别所修饰的属性或者方法在当前的Swift源文件里可以访问。

3、internal(默认访问级别,internal修饰符可写可不写)
internal访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。
如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。
如果是App代码,也是在整个App代码,也是在整个App内部可以访问。

4、public
可以被任何人访问。但其他module中不可以被override和继承,而在module内可以被override和继承。

5,open
可以被任何人使用,包括override和继承。

访问顺序:
现在的访问权限则依次为:open,public,internal,fileprivate,private。

Open 和 Public 级别可以让实体被同一模块源文件中的所有实体访问,在模块外也可以通过导入该模块来访问源文件里的所有实体。通常情况下,你会使用 Open 或 Public 级别来指定框架的外部接口。Open 和 Public 的区别在后面会提到。
Internal 级别让实体被同一模块源文件中的任何实体访问,但是不能被模块外的实体访问。通常情况下,如果某个接口只在应用程序或框架内部使用,就可以将其设置为 Internal 级别。
File-private 限制实体只能在其定义的文件内部访问。如果功能的部分细节只需要在文件内使用时,可以使用 File-private 来将其隐藏。
Private 限制实体只能在其定义的作用域,以及同一文件内的 extension 访问。如果功能的部分细节只需要在当前作用域内使用时,可以使用 Private 来将其隐藏。
Open 只能作用于类和类的成员,它和 Public 的区别如下:
Public 或者其它更严访问级别的类,只能在其定义的模块内部被继承。
Public 或者其它更严访问级别的类成员,只能在其定义的模块内部的子类中重写。
Open 的类,可以在其定义的模块中被继承,也可以在引用它的模块中被继承。
Open 的类成员,可以在其定义的模块中子类中重写,也可以在引用它的模块中的子类重写。

因为OC 的局限性, 使得iOS 开发组件化编程变得不可能,得益于面向对象语言的特性 (封装,继承,多态) 在我们熟悉的设计模式中渐渐形成统一的软件开发思想.
在抽取某些功能作为基类的不断运用中,代码的可移植性逐渐减弱. 就如同一棵树,从主干到各个分支,每个分支再长成细枝末叶.代码的耦合性也相应增加.
随着苹果 swift 语言的推出, 对于传统OC 语言取其精华,弃其糟粕. 加上开源社区众大神的齐力维护.逐渐成为一门非常优秀的高级语言.
其中 swift中的面向协议编程思想 就是其中很有代表性的一项优秀组成部分.

3.静态方法和实例方法的区分

 a).静态方法常驻内存,实例方法不是,所以静态方法效率高但占内存。事实上,方法都是一样的,在加载时机和占用内存上,静态方法和实例方法是一样的,在类型第一次被使用时加载。调用的速度基本上没有差别。

b).静态方法在堆上分配内存,实例方法在堆栈上。事实上所有的方法都不可能在堆或者堆栈上分配内存,方法作为代码是被加载到特殊的代码内存区域,这个区域是不可写的。

c).实例方法需要先创建实例才可以调用,比较麻烦,静态方法不用,比较简单。

d).静态方法是静态绑定到子类,不是被继承。

e).一般使用频繁的方法用静态方法,用的少的方法用动态的。静态的速度快,占内存。动态的速度相对慢些,但调用完后,立即释放类,可以节省内存,可以根据自己的需要选择是用动态方法还是静态方法。

f).静态方法修改的是类的状态,而对象修改的是各个对象的状态。

g).类的实例调用是在类的生命周期中存在,当类没有了以后,对应的实例也就没有了,对应的方法也就没有了。静态类不然,只要你引用了那个静态类的命名空间,它就会一直存在,直到我们推出系统。

Swiftify 一个比较好的自动化工具

oc中创建swift文件要建立qiaoi

Swift和OC的区别有很多,这里简要总结这几条:

Swift Objective-C
语言特性 静态语言,更加安全 动态语言, 不那么安全
语法 更精简 冗长
命名空间 有 无
方法调用 直接调用,函数表调用,消息转发 消息转发
泛型/元组/高阶函数 有 无
语言效率 性能更高,速度更快 略低
文件特性 .swift 单文件 .h/.m包含头文件
编程特性 可以更好的实现函数式编程/响应式编程 面向对象编程

4、if let 、 guard let 的用法

if let 处理空的情况

guard let 缩减else 代码逻辑更清晰

缩减代码量,安全处理数据逻辑

Swift没有property,也没有copy,nonatomic等属性修饰词,只有表示属性是否可变的let和var。

1、Swift语句中不需要加分号;。
2、关于Bool类型更加严格,Swift不再是OC中的非0就是真,真假只对应true和false。
3、Swift类内一般不需要写self,但是闭包内是需要写的。
4、Swift是强类型语言,必须要指定明确的类型。在Swift中Int和Float是不能直接做运算的,必须要将他们转成同一类型才可以运算。
5、Swift抛弃了传统的++,–运算,抛弃了传统的C语言式的for循环写法,而改为for-in。
6、Swift的switch操作,不需要在每个case语句结束的时候都添加break。
7、Swift对enum的使用做了大的很扩展,可以支持任意类型,而OC枚举仅支持Int类型,如果要写兼容代码,要选择Int型枚举。
8、Swift代码要想被OC调用,需要在属性和方法名前面加上@objc。
9、Swift独有的特性,如泛型,struct,非Int型的enum等被包含才函数参数中,即使添加@objc也不会被编译器通过。
10、Swift支持重载,OC不支持。
11、带默认值的Swift函数再被OC调用时会自动展开。

id类型和AnyObject

id 是一种通用的对象类型,它可以指向属于任何类的对象,在OC中即是可以代表所有继承于NSObject的对象。
AnyObject可以代表任何class类型的实例。
Any可以代表任何类型,甚至包括func类型。

引用类型和值类型
struct 和 enum 是值类型,类 class 是引用类型。
String,Array和 Dictionary都是结构体,因此赋值直接是拷贝,而NSString, NSArray 和NSDictionary则是类,所以是使用引用的方式。所以并不能动态编译。
struct 比 class 更“轻量级”,struct 分配在栈中,class 分配在堆中。

protocol(协议/代理)

Swift中对protocol的使用拓宽了许多,不光是class对象,struct和enum也都可以实现协议。需要注意的是struct和enum为指引用类型,不能使用weak修饰。只有指定当前代理只支持类对象,才能使用weak。将上面的代码转成对应的Swift代码,就是

通知
通知名由字符串变成了NSNotification.Name的结构体
NotificationCenter.default.post(name: NSNotification.Name(rawValue: “NotificationName”), object: self)

OC可以通过是否将方法声明在.h文件表明该方法是否为私有方法。Swift中没有了.h文件,对于方法的权限控制是通过权限关键词进行的,各关键词权限大小为: private < fileprivate < internal < public < open

初始化方法
对于初始化方法OC先调用父类的初始化方法,然后初始自己的成员变量。Swift先初始化自己的成员变量,然后在调用父类的初始化方法。

Swift中全局变量是懒加载,在AppDelegate中被初始化,之后所有的调用都会使用该实例。这保证了全局变量的构造器(initializer)只会被调用一次

类型特型

1类型安全,编译代码时进⾏类型检查
2类型推断,C或者Objective-C ⽐起来 Swift 很少需要声明类型

类型转换

as 从派生类转换为基类,向上转型(upcasts)

as! 向下转型(Downcasting)时使用。由于是强制类型转换,如果转换失败会报 runtime 运行错误

as? 和 as! 操作符的转换规则完全一样。但 as? 如果转换不成功的时候便会返回一个 nil 对象。

类型别名

布尔值:严格的布尔类型

oc没有的 (元组和可选类型)

元组:Swift 增加OC中没有的⾼阶数据类型⽐如元组(Tuple)(404, “Not Found”)

1.赋值:位数顺序对应,只需要⼀部分元组值,分解的时候可以把要忽略的部分⽤下划线( _ )标记

2.元素访问:通过下标来访问元组中的单个元素,元素命名,通过名字来获取这些元素的值

可选类型 来处理值可能缺失(如类型转换),swift中的nil不是指针(oc:指向不存在对象的指针),它是⼀个确定的值,⽤来表示值缺失,不只修饰是对象类型

可选绑定: if 语句和 nil ⽐较来判断⼀个可选值是否包含值

! 来获取⼀个不存在的可选值会导致运⾏时错误。使⽤ ! 来强制解析值之前,⼀定要确定可选包含⼀个⾮ nil 的值。

错误处理

throws ⼀个函数可以通过在声明中添加 throws 关键词来抛出错误消息。当你的函数能抛出错误消息时,你应该在表达式中前置 try 关键词。

func canThrowAnError() throws { // 这个函数有可能抛出错误

}

do{
try canThrowAnError() // 没有错误消息抛出
}catch {
// 有⼀个错误消息抛出
}

assert(age >= 0, “A person’s age cannot be less than zero”)

运算符

区间运算符:a…<b
半开:for i in 0…<count,单侧:for name in names[2…]

空合运算符 ??

操作符 + 可实现数组和字符串的拼接和合并

let s = " / 2 3 4 ? / "
// 替换 replacingOccurrences(of: " ", with: “-”))
// 分割 s.components(separatedBy: “/”)
// 拼接let a = [“1”, “2”, “3”] a.joined(separator: “-”)

数组的遍历
var someInts = Int

for item in shoppingList

for (index, value) in shoppingList.enumerated() .enumerated()区分了数组和字典

集合:当集合元素顺序不重要时或者希望确保每个元素只出现⼀次时可以使⽤集合⽽不是数组。
遍历
for (airportCode, airportName) in airports

for airportCode in airports.keys

for airportName in airports.values

某个字典的键集合或者值集合来作为某个接受 Array
let airportCodes = String
let airportNames = String

控制流

Repeat-While,和 while 的区别是在判断循环条件之前,先执⾏⼀次循环的代码块。然后重复循环直到条件为 false

switch 条件的不存在隐式贯穿
1.Swift 中,当匹配的 case 分⽀中的代码执⾏完毕后,程序会终⽌ switch 语句,⽽不会继续执⾏下⼀个 case 分⽀
、不需要在case 分⽀中显式地使⽤ break 语句。需要贯穿使⽤ fallthrough
2.每⼀个 case 分⽀都必须包含⾄少⼀条语句,为了让单个 case 同时匹配 a 和 A ,可以将这个两个值组合成⼀个复合匹配,并且⽤逗号分
开,case 分⽀的模式也可以是⼀个值的区间,case 分⽀的模式可以使⽤ where 语句来判断额外的条件。

case “a”: // ⽆效,这个分⽀下⾯没有语句
case “A”:
print(“The letter A”)

case “a”, “A”:
print(“The letter A”)

case 1…<5:
naturalCount = “a few”

guard 语句来要求条件必须为真时

guard let name = person[“name”] else {
return
}

引用类型和值类型
swift 结构体,枚举和元组都是值类型,数组,字典,集合,整,浮点字符串也都是结构体都是值类型在内存上是储存在栈上

闭包的本质还是函数,函数和闭包都是引用类型

Swift的闭包捕获变量是在执行闭包时捕获,在闭包内部对外部变量值的改变也会影响到外部,OC的block是在block体内捕获,在函数内部与外部修改这个变量值不会产生相互影响,Swift捕获列表 使用[] 加in 实现跟oc一样的效果

结构体和类的抉择是那些条件下用结构体:

结构体的主要目的是用来封装少量相关简单数据值。
有理由预计一个结构体实例在赋值或传递时,封装的数据将会被拷贝而不是被引用。
任何在结构体中储存的值类型属性,也将会被拷贝,而不是被引用。
结构体不需要去继承另一个已存在类型的属性或者行为。

与objective-c不同的是,structure和enumeration也可以拥有方法(method),其中方法可以为实例方法(instance method),也可以为类方法(type method),实例方法是和类型的一个实例绑定的。实例方法中是不可以(不建议)修改值类型的属性,如果要修改用 mutating修饰

private (set) 修饰变量的赋值范围

扩展和 Objective-C 的分类很相似。(与Objective-C 分类不同的是,Swift 扩展是没有名字的。)

BehaviorRelay 通过vaule访问到 信号转换成值 (只读属性)
通过accept 接受信号 Observable 的值 可以将 Observable转换成 BehaviorRelay
asObservable 将 BehaviorRelay转化成 Observable

将 Observable 转换为 Driver 使用 asDriver() 方法,Driver 转换为 Observable 使用 asObservable() 方法
通过drive方法将其信号绑定到UI控件上

rxswift tablevie或者collectionView 牵涉到重用就要解决销毁重复添加问题,解决是
1.基类封装 在重用方法中重置重用袋

在oc 中的枚举类型的成员变量是整型,第一个成员变量的值默认为0,第二个为1,顺次递增。但是在swift里,枚举类型的成员变量类型可以为字符串、整型、浮点数

在Swift中,一个实例可以是Class,也可以是Struct或Enum,所以,为了表示一个实例是否具有比较是否相等的能力,就要依靠 protocol来实现了

Equalable协议定义了比较两个实例的方式
在Objective-C中,基本上所有的实例都是NSObject或其子类的实例。由于NSObject有一个方法isEqual,因此所有的实例都具有了这个比较是否相等的能力
但是在Swift中,一个实例可以是Class,也可以是Struct或Enum,所以,为了表示一个实例是否具有比较是否相等的能力,就要依靠 protocol来实现了。
能够判断是否相等的类型都要实现这个协议:对于实现这个协议的类型,想判断二者是否相等的时候,就可以使用==运算符来判断了。

Provider

MultiProvider:包裹根节点

Providers:预先定义共享的Model provider 常量或者方法 ChangeNotifierProvider 数据改变而被通知更新 ChangeNotifierProxyProvider 一个ModelA依赖另一个ModelB,ModelB更新

Provider.of(context) / Widget Consumer

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值