关于objective-c:初探SwiftUI打通任督二脉

45次阅读

共计 7481 个字符,预计需要花费 19 分钟才能阅读完成。

序言

开年的第一篇文章,明天分享的是 SwiftUI,SwiftUI 进去好几年,之前始终没学习,所以当初才开始;如果大家还留在 iOS 开发,这们语言也是一个趋势;目前待业中 …. 不得不说已逝的 2023 年,大家开始都抱着一解封,经济都会向上转好,可是事实不是咱们设想那样;目前我也在学习 SwiftUI,并且致力找工作中 ….;至于 2024 年经济如何,咱们作为老百姓在大环境和寰球经济影响下;坦然面对,晋升本人。这里不得不说国人百折不挠的精力。“卷” 致力吧 Coding 人

SwiftUI 体验

Xcode 创立我的项目之后呈现工程默认创立的 UI 界面;如下

一开始心里对本人说:"SwiftUI 作为 iOS 开发新的 UI 体系,为啥初创的我的项目这么多代码,给初学者看到,一种压迫感,心想这语法好简单,不想学了";不论你是不是这样心里,我刚开始看见,这么一坨代码,没什么心理,于是索性删掉;按本人能了解学习的形式来操作;于是做了简化:

import SwiftUI
import SwiftData

struct ContentView: View {
   
    var body: some View {Text("hello,word”)
    }
}

#Preview {ContentView()
        .modelContainer(for: Item.self, inMemory: true)
}

关键字 some

关键字 some 啥玩意儿,齐全生疏;先看看 View; 点击进入源码构造查看:

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View {

    /// The type of view representing the body of this view.
    ///
    /// When you create a custom view, Swift infers this type from your
    /// implementation of the required ``View/body-swift.property`` property.
    associatedtype Body : View

    @ViewBuilder @MainActor var body: Self.Body {get}
}

一堆英文注解预计大家不喜爱看,我就没贴出来了;简略来说:
View 是一个泛型协定,它定义了所有视图类型须要遵循的接口,通过 some 润饰;示意 “ 我返回一个满足View 协定的某种类型 ”。some 关键字通知 Swift,尽管咱们晓得 body 必须返回一个View,但咱们不确定具体是哪种 View(例如,TextImageVStack 等)。

协定里有一个 associatedtypebody,其实这种协定就是当作束缚模式应用;只有恪守这种协定编译器每次闭包中返回的肯定是一个确定,恪守View 协定的类型。

那么苹果工程师利用 Swift5.1 Opaque return types个性, 开发者提供了一个灵便的开发模式,抹掉了具体的类型,不须要批改公共 API 来确定每次闭包的返回类型,也升高了代码书写难度。(学学苹果那些大神思维,不错)

在来看看Preview

struct ContentView_Previews:PreviewProvider{
    static var previews: some View{ContentView()
        
    }
}

PreviewProvider就一个协定类,它的额作用提供 swiftUI 不必运行,就能间接看到 UI 渲染变动,我感觉这个挺好,缩小开发人员对 UI 运行测试次数和工夫,而 previews 就是一个动态属性,返回一个 View 对象,用于在预览面板中展现。

@State 属性包装器

@State 属性包装器 解决 UI 界面上,数据同步以及及时刷新的性能。一般来说数据更新完,界面 UI 同时更新。在 SwiftUI外面,视图中申明的任何状态、内容和布局,源头一旦产生扭转,会自动更新视图,因而,只须要一次布局,这个时候呈现了@State,它来解决与 UI 之间数据状态问题。

它的概念就是:@State 是一个属性包装器(property wrapper),用于申明状态属性(state property)
当状态属性发生变化时,SwiftUI 会自动更新视图以反映最新的状态。

属性的值被存储在非凡的内存区域中,这个区域与 View struct 是隔离的 至于被它润饰的属性内存存储与散布当初无从得悉,还没学习到那么深刻,这事儿慢慢来,不是一天两天的,先上个代码看看它怎么应用的:

import SwiftUI

struct StateBootcamp: View {
    
    @State var bgkColor:Color = Color.blue
    @State var cut:Int = 0
    
    var body: some View {
        
        ZStack{
            
            bgkColor
                .ignoresSafeArea(.all)
            
            VStack(spacing: 20){Text("Hello, World!”)
                    .font(.title)
                
                Text("count:\(cut)”)
                    .font(.largeTitle)
                
                HStack(spacing: 20){Button("Button01") {
                        cut+=1
                        bgkColor = Color.red
                    }
                    .font(.title)
                    .foregroundColor(.white)
                    
                    Button("Button02") {
                        cut-=1
                        bgkColor = .purple
                    }
                    .font(.title)
                    .foregroundColor(.white)
                }
                Button(" 默认”){
                    cut=0
                    bgkColor = .blue
                }
                .font(.title)
                .foregroundColor(.white)
            }
        }
    }
}

#Preview {StateBootcamp()
}

其实一看代码,就一幕了然,晓得它的应用与作用;如果你写过 swift 代码,这些货色很好了解,然而只会 OC, 那么我倡议你学习下 swift;在来看 swiftUI 语法糖才更好了解。

在看看源码:

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen @propertyWrapper public struct State<Value> : DynamicProperty {public init(wrappedValue value: Value)
    public init(initialValue value: Value)
    public var wrappedValue: Value {get nonmutating set}
    public var projectedValue: Binding<Value> {get}
}


@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension State where Value : ExpressibleByNilLiteral {

    /// Creates a state property without an initial value.
    ///
    /// This initializer behaves like the ``init(wrappedValue:)`` initializer
    /// with an input of `nil`. See that initializer for more information.
    @inlinable public init()}

能够看到 State 是一个构造体,由 @propertyWrapper 包装的。@propertyWrapper是属性包装器。property wrapper 做的事件大体如下:

-   为底层的存储变量 `State<Int>` 主动提供一组 **getter** 和 **setter** 办法,构造体内保留了 `Int` 的具体数值;-   在 body 首次求值前,将 `State<Int>` 关联到以后 `View` 上,为它在堆中对应以后 `View` 调配一个存储地位。-   为 `@State` 润饰的变量设置察看,当值扭转时,触发新一次的 `body` 求值,并刷新 UI。

SwiftUI根底组件

Spacer 垫片:先贴贴代码

import SwiftUI

struct SpacerBootcampDemo: View {
    var body: some View {Text("Spacer UP”)
            .font(.largeTitle)
        
        Spacer()
            .frame(width: 37)
            .background(.blue)
        
        Text("Spacer Down”)
            .font(.largeTitle)
        
    }
}

#Preview {SpacerBootcampDemo()
}

在看看效果图:

总结:Spacer 是一个灵便的空间视图,它的次要作用是在布局中主动调整本身的高度和宽度,以填满特定的空间;简略来说,它就是一个垫片,调整本身视图的高度,如果它四周有其余视图,也会受到 Spacer 影响。

ScrollView 如果你之前应用 UIkit 框架开发,在用 SwiftUI,一下有点不适应,代码和之前的 UIkit 开发模式不太一样,然而大大缩短 UI 编写工夫;先上代码:


import SwiftUI

struct ScollViewBootcamp: View {
    
    var body: some View {
        
        ScrollView{
            LazyVStack{ForEach(0..<20){(idx) in
                    
                    VStack {Text("Hello, World!”)
                            .font(.title)
                            .foregroundStyle(.white)
                            .frame(width: UIScreen.main.bounds.width-20,height: 350)
                            .background(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0..<215)/255.0, green: CGFloat.random(in: 0..<235)/255.0, blue: CGFloat.random(in: 0...247)/255.0, alpha: 0.9)))
                            .clipShape(RoundedRectangle(cornerRadius: 10))
                        
                        Rectangle()
                            .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0...187)/255.0, green: CGFloat.random(in: 0..<210)/255.0, blue: CGFloat.random(in: 0...237)/255.0, alpha: 0.9)))
                            .frame(width: UIScreen.main.bounds.width-20,height: 530)
                            .clipShape(RoundedRectangle(cornerRadius: 10))
                        
                        
                        ScrollView(.horizontal,showsIndicators: false,content: {
                            LazyHStack{ForEach(0..<10){
                                    idx in
                                    Rectangle()
                                        .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0...167)/255.0, green: CGFloat.random(in: 0...131)/255.0, blue: CGFloat.random(in: 0...89)/255.0, alpha: 0.9)))
                                        .frame(width: 200, height: 300)
                                        .clipShape(RoundedRectangle(cornerRadius: 10))
                                    
                                }
                            }
                        })
                        .padding(.leading,10)
                        .padding(.trailing,10)
                        
                        
                    }
                }
            }
            .frame(width:UIScreen.main.bounds.width)
            
        }
    }
}


#Preview {ScollViewBootcamp()
}

上图看看成果:

简略几句就能实现 ScrollView 的滑动成果;十分不便。

LazyVGrid 网格布局,先上代码:

import SwiftUI

struct GridViewBootcamp: View {
    
    let columns=[GridItem(.flexible(),spacing: 6   ,alignment: .center),
        GridItem(.flexible(),spacing: 6    ,alignment: .center),
        GridItem(.flexible(),spacing: 6  ,alignment: .center),
    ]
    
    var body: some View {
        
        ScrollView{
            LazyVGrid(columns: columns,
                      alignment: .center,
                      spacing: 6,
                      pinnedViews: [.sectionHeaders],content:
                        {Section(content: {}, header: {Text("section header 一”)
                        .font(.largeTitle)
                        .foregroundStyle(.blue)
                        .frame(width: UIScreen.main.bounds.width,height: 100,alignment: .leading)
                })
                
                ForEach(0..<41){
                    index in
                    Rectangle()
                        .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0..<255)/255.0, green: CGFloat.random(in: 0..<255)/255.0, blue: CGFloat.random(in: 0...255)/255.0, alpha: 0.9)))
                        .frame(height: 50)
                }
                
                //———
                Section { } header: {Text("section header 二”)
                        .font(.largeTitle)
                        .foregroundStyle(.blue)
                        .frame(width: UIScreen.main.bounds.width,alignment: .leading)
                    
                }
                
                ForEach(0..<41){
                    index in
                    Rectangle()
                        .fill(Color.init(cgColor: CGColor(red: CGFloat.random(in: 0..<255)/255.0, green: CGFloat.random(in: 0..<255)/255.0, blue: CGFloat.random(in: 0...255)/255.0, alpha: 0.9)))
                        .frame(height: 50)
                }
                
            })
            .padding(.leading,6)
            .padding(.trailing,6)
            .background(.gray)
        }.background(.blue)
    }
}

#Preview {GridViewBootcamp()
}

效果图:

总结:LazyVGrid大家看到这个单词有个 Lazy 懒加载的意思,它的外部加载 item 简略来说,就是当视图须要时,才会执行 item 内容渲染性能,展现 UI 上。也就这点留神。

SafeArea平安区域:

import SwiftUI

struct SafeAreaBootcamp: View {
    var body: some View {
        GeometryReader{
            src in
            Rectangle()
                .fill(.blue)
                .frame(maxWidth: .infinity,
                       maxHeight: .infinity)
        }
    }
}

#Preview {SafeAreaBootcamp()
}

效果图:

能够看到上下边距存在平安区域的,如果禁用平安区域,应用 ignoresSafeArea(.all) 能够去掉。

代码如下:

最初说说 SwiftUI 函数表白

上上代码:


import SwiftUI

struct ExtractFunctionsBootcamp: View {
    
    @State var bgc:Color = .red
    
    var body: some View {normolView}
    
    var normolView : some View {setUI()
    }
    
    func chageColor() -> Void {self.bgc = .red}
    
    func setUI()->some View {
        return ZStack{
            
            bgc
                .ignoresSafeArea(.all)
            
            VStack(spacing: 20, content: {Text("Hello, World!”)
                    .font(.largeTitle)
                
                Button(action: {bgc = .brown}, label: {Text(“Button”)
                        .font(.largeTitle)
                        .foregroundStyle(.white)
                })
                
                Button {self.chageColor()
                } label: {Image(systemName:“button.horizontal.top.press”)
                        .resizable()
                        .foregroundColor(.white)
                        .aspectRatio(contentMode: .fill)
                        .frame(width: 50,height: 50)
                }
            })
        }
    }
}


#Preview {ExtractFunctionsBootcamp()
}

其实函数表白跟咱们 swift 语法糖一样;func 命名;这点和 swift 语法糖没什么区别。

总结(说说我的感想)

长处:

简洁性:Swift,SwiftUI 语法简洁,编写代码变得更加容易和疾速。

安全性:是一种类型平安的编程语言,能够在编译时检测类型谬误,这帮忙咱们防止许多常见的谬误,进步代码的品质和可靠性。

互操作性:它与 Objective- C 语言无缝互连接,是的 OC 与 swift 代码混编变的更加便捷。

说完长处在说毛病

性能限度:尽管 SwiftUI 提供了许多常见的 UI 组件,但与 UIKit 相比,性能依然绝对无限。在某些简单的界面需要下,可能须要应用 UIKit 来实现。

谬误提醒不明确:有时 SwiftUI,SwiftUI 的谬误提醒可能不够明确,导致难以定位问题。

UIkit 与 SwiftUI 不足无缝兼容:两者兼容性不够现实,这在业务开发中,你可能能力发现。

目前苹果与市面大量利用也在应用 Swift,SwiftUI 开发利用,这们语言在利用中占有读也是成倍增长。

路漫漫其修远兮, 吾将上下而求索

后续更新中……….

正文完
 0