第二十五篇:SwiftUI使用
swiftUI是声明式,可夸平台(macOs,tvOs,watchOS,iOS)。传统的UIKit是指令式。
UIKit和swifitUI可以互相通讯 。
为什么要推出swiftUI:
9211669780399_.pic.jpg 9221669780685_.pic.jpg 9231669780940_.pic.jpg 9241669781059_.pic.jpg 9251669781091_.pic.jpg
swiftUI用struct结构体来表示UI,占用大小小比Class(oc里面的)。没有任何继承下来的东西。Modifies Library许多拖拽的UI。其中其还有markdown语法。
下面是一些SwiftUI里的一些控件
timelineview可以按计划刷新view,asyncImage加载图片等,canvas绘制,textEditor,picker地址选择器,progressview进度条,gradient颜色的渐变,badge,Tabview(类似oc里的tabbar),onopenurl,DatePicker,contextMenu,Mapview(地图),List列表(类似oc里的tableview),Form(表单)(数据少可以用Form,列表内就用List),scrollview,Grid(类似oc里的UIcolllectionview),Videoplayer,NavigationView(可以进行点击(navigationLink)),Alert弹框,toolbar,fullScreenCover(类似oc里的莫态势图),controlGroup,alignment(对其),positon(是指中心点位置)
@state进行特定的刷新(和flutter里的provider很像)
VStack里最多有10个view
UIkit进行布局,坐标系原点在左上角。swiftUI是弹性布局,没有坐标系概念
HStack和VStack进行弹性布局的一些容器
lazyVStack(可以使用懒加载)也是容器
苹果官方说了两种时候其不起作用:
1)lazyview的内容,超出了这个frame的任何边界
2)包含lazyview的视图,显式的设置他的frame
下面的lazyVStack需要配合foreach,scrollview使用才会起到一个懒加载的效果,不会重复的去创建
7471669805469_.pic.jpg
viewBuilder实现一个闭包,返回一个范型(可以是view,label等等)
swiftUI里的状态改变
1)@State属性包装器
将@State用于属于单个视图的简单属性。通常应将其标记为私有。
@State不适合在对象之间进行传递
2)@ObservedObject
对于更复杂的属性-当您要使用的自定义类型可能具有多个属性和方法,或者可能在多个视图之间共享时,通常会使用@ObservedObject。
这与@State非常相似,不同之处在于,我们现在使用的是外部引用类型,而不是简单的本地属性(例如字符串或整数),与@ObservedObject一起使用的任何类型都应符合ObservableObject协议
3)@EnvironmentObject
还有另一种可以使用的属性包装器,即@EnvironmentObject。这个值可通过应用程序本身提供给视图,它是每个视图都可以读取的共享数据。因此,如果您的应用程序具有一些重要的模型数据,所有视图都需要读取这些数据,则可以将其从一个视图到另一个视图,或者只是将其置于每个视图都可以即时访问它的环境中。
当您需要在应用程序中传递大量数据时,可以将@EnvironmentObject视为一种极大的便利。由于所有视图都指向同一个模型,因此,如果一个视图更改了模型,则所有视图都会立即更新-这样就不会冒着使应用程序的不同部分不同步的风险
4)@Binding
但是与@State区别在于@Binding用于不同视图之间的参数传递,@Binding 和@ObservedObbjecg一样都是传递引用。
struct和class区别
struct是值类型,值类型的变量包含数据,会进行值copy,存储在栈中
class是引用类型,引用类型的变量,存储对他们的数据引用
\.self的使用
当一个对象遵从于Identifiable时,SwiftUI会自动使用它的id来进行“唯一化“(可以理解为一种“ForEach”一样的遍历);但是当我们没让对象遵从于Identifiable时,我们也可以用一个我们知道是唯一的的key path进行排序(如书籍的ISBN号);当所有值都不一定是唯一的时,我们就会使用\\.self。
在Swift中被称为“关键路径”(key path),可以用于在另一个对象上指定VAR。
首先,\.self可以用来遍历一些简单的结构:
当我们把\.self作为一个标识符(identifier)——一个struct就是一个struct,它其中只存着内容,并没有一个识别码一样的identification information,所以\.self其实给struct中的每一组值都设立了一个哈希值,并用这个独一无二的哈希值进行识别以及遍历(ForEach)。
7491669812631_.pic.jpg
@Appstorage使用
其是一个全局的存储
@Appstorage类似oc里的nsuserdefault,数据存储。使用方法和state一样
当值改变时候其会自动存储,轻量级的存储
@Scenestorage使用
只能用到view上面 (和@Appstorage的区别)
@Scenestorage也是数据的存储,其是swiftUI接管的
ObservableObject的使用
下面首先是定义一个ObservableObject的协议,然后用@Published进行一个修饰,然后运行后模拟器上的值会自加
7531669813811_.pic.jpgwillset的使用
其是进行将要变化的时候处理
7541669814053_.pic.jpg
@environmentObject的使用
可以通过多个界面进行传值使用,可以进过跳页面传数据
7561669814607_.pic.jpg@UIViewcontroller的使用
在使用的时候,因为swiftUI没有controller的概念,其都是view,所以我们需要通过UIViewControllerRepresentable这个协议把controller变成view,通过这个协议也可以使得swiftUI界面跳转到controller界面
ViewModifier的使用
ViewModifier就是属性修饰器,其可以把许多相同的属性写在viewModifier里,然后供view使用。
7581669816344_.pic.jpg响应式编程Conbine框架的使用
7601669818130_.pic.jpg 7611669818207_.pic.jpgFuture的使用和Promise的使用
Future遵守Publisher协议
下面是官方Future源码
final public class Future<Output, Failure> : Publisher where Failure : Error {
/// A type that represents a closure to invoke in the future, when an element or error is available.
///
/// The promise closure receives one parameter: a `Result` that contains either a single element published by a ``Future``, or an error.
public typealias Promise = (Result<Output, Failure>) -> Void
/// Creates a publisher that invokes a promise closure when the publisher emits an element.
///
/// - Parameter attemptToFulfill: A Future/Promise
that the publisher invokes when the publisher emits an element or terminates with an error.
public init(_ attemptToFulfill: @escaping (@escaping Future<Output, Failure>.Promise) -> Void)
/// Attaches the specified subscriber to this publisher.
///
/// Implementations of ``Publisher`` must implement this method.
///
/// The provided implementation of ``Publisher/subscribe(_:)-4u8kn``calls this method.
///
/// - Parameter subscriber: The subscriber to attach to this ``Publisher``, after which it can receive values.
final public func receive<S>(subscriber: S) where Output == S.Input, Failure == S.Failure, S : Subscriber
}
它包含一个Promise类型和一个带有@escaping闭包的初始化函数。
Future和PassthroughSubject、CurrentValueSubject一样,是一个类,不同的是Future实现的是Publiser协议,而PassthroughtSubject和CurrentValueSubject实现的是Subject协议,所以后两个可以使用send方法,而Future不能。
promise使用
Promise是Future的最终结果。就像英文名所表现的那样,一个是承诺,一个是未来。我们要用承诺来初始化一个未来。Future和Promise需要配套使用。
从Future源码可以看到,Future的初始化Init函数中需要实现一个@escaping闭包,闭包类型就是Promise。Promise的本质可以理解为是一个接收单个Result类型参数的闭包。
let future = Future<Int, Never> { promise in
// 1
promise(.success(1))
}
上面的代码是Future的初始化及发布的简单过程,注释为1的行,表示的动作就是,我承诺给你一个数据为Int(1),可以是现在就给予,也可以是在未来给予,比如使用DispatchQueue.main.async 包裹 promise
PropertyWrapper的使用
7621669819364_.pic.jpg 7631669819870_.pic.jpgnever是一个无实例类型