刚接触Flutter开发时,不管是为了性能还是项目代码简洁等原因,总归还是会选择一个合适的状态管理工具。但是看着茫茫多的选择还是感觉无从下手,当然我也一样。下方记录一下各种状态管理(Riverpod、Provider、Getx)的使用,以便后续遇到其他项目使用不同状态管理时能快速上手。也希望为看到这篇文章的同学提供一些参考。
Riverpod
使用的前提需要注意,需要使用ProviderScope包裹父级节点。
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
示例 1:
1 | 输入:root = [1,null,2,3] |
示例 2:
1 | 输入:root = [] |
1 | /** |
解题思路:
字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。
示例1:
输入:s1 = “waterbottle”, s2 = “erbottlewat”
输出:True
示例2:
输入:s1 = “aa”, s2 = “aba”
输出:False
提示:
字符串长度在[0, 100000]范围内。
说明:
你能只调用一次检查子串的方法吗?
1 | class Solution { |
解题思路:
设计一个支持 push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
示例:
1 | 输入: |
提示:
pop、top 和 getMin 操作总是在 非空栈 上调用。
1 | class MinStack { |
解题思路:
题目要求我们从栈元素中找到最小值,按照正常想,我们都会遍历一遍栈的元素,但是这样时间复杂度就是O(n),题目要求是O(1),一般遇到这种问题,就需要空间换时间了。
使用链表,在每个节点保存当前的最小值,每次push都记录当前元素对应的最小值,每个节点都一一对应一个最小值,这样子getMin时间复杂度就是O(1),同道理,这里用两个栈也可以做到一一对应也能解决。
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
**示例 **
1 | 输入:head = [1,2,6,3,4,5,6], val = 6 |
1 | public class ListNode { |
解题思路:
这里用一个虚拟头结点来作为新链表的头结点会让代码更加的简洁,遍历传进来的链表,判断当前的链表是否是需要删除的如果不是需要删除的,让新链表尾结点下一个指向它,也就是尾部结点也是当前结点,最后把尾部结点置空,返回新节点头的下一个结点。
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例 :
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
1 | func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) { |
解题思路:
双指针法,从后面插入替换合并,把nums2数值添加到nums1,如果在前面插入会替换到后面的数字
只要nums2的指针索引>=0代表还没有合并结束,只要成功合并一次,两个指针索引都需要向后移动一位
这里还需要考虑到比如nums1的长度比nums2 数组长度短的情况,所以 else 里就是 // i1 < 0 || nums2[i2] >= nums1[i1] 这里i1已经为0了 这里直接把nums2的数字往nums1数组合并
这里解题思路用到了归并排序算法:
作为一个移动端iOS开发,小程序也是有必要学习的,学好小程序的基本流程,会发现跟iOS原生开发很多都相似的,比如每个界面都有它的生命周期,数据绑定,响应事件等等,而且微信团队把它封装得非常易用,只要看文档,补充下CSS的知识就可以上手开发。
clssname .clssname
1 | .clssname .clssname{ |
代表 clssname 里的clssname样式更改
clssname view
1 | .clssname view{ |
代表 clssname 里所有的view样式更改
Updating took more than 5 seconds
花了点时间查找问题,最后发现是因为初始化数据库写在AppDelegate,写在SceneDelegate就没事了!
@State属性允许修改Struct的属性,这些属性在普通的Struct里面是不允许修改的。当把@State放置到属性前,该属性实际上会被放到Struct的外部存储起来,这意味着SwiftUI能够随时销毁和重建Struct而不会丢失属性的值。
@State包装的属性通常是设置成私有的,不让外部使用。如果想让外部使用,则应该使用@ObservedObject和@EnvironmentObject,他们能够使外部修改属性后,状态能够得到改变。
建议把@State包装的属性都设置成私有
@Published是SwiftUI最有用的包装之一,允许我们创建出能够被自动观察的对象属性,SwiftUI会自动监视这个属性,一旦发生了改变,会自动修改与该属性绑定的界面。
1.首先需要遵循ObservableObject属性
1 | class Bag: ObservableObject { var items = [String]() } |
2.包装属性
1 | class Bag: ObservableObject { @Published var items = [String]() } |
这样就完成了。@Published包装会自动添加willSet方法监视属性的改变。
@ObservedObject告诉SwiftUI,这个对象是可以被观察的,里面含有被@Published包装了的属性。
@ObservedObject包装的对象,必须遵循ObservableObject协议。也就是说必须是class对象,不能是struct。
@ObservedObject允许外部进行访问和修改。
@EnvironmentObject包装的属性是全局的,整个app都可以访问
需要注意的是,不需要给定默认值,由于该属性是整个app都可以访问的,SwiftUI会自动的从环境中取出来。
当有这样一个场景,A->B->C->D->E->F,A界面的数据要传递给F界面,假如使用@ObservedObject包装,则需要一层一层传递,而使用@EnvironmentObject则不需要,直接在F界面,通过SwiftUI环境直接取出来就行。
需要注意的是,当界面显示时,就会去环境中取,但是,假如之前没有把属性放到环境中,则程序会崩溃。
@Environment与@EnvironmentObject作用是不同的,@Environment是从环境中取出预定义的值,比如获得当前是暗黑模式还是正常模式,屏幕的大小等等。
1 | @Environment(\.horizontalSizeClass) var horizontalSizeClass |
@Binding也是非常重要的一个包装,声明一个属性是从外部获取的,并且与外部是共享的。相当于外部传过来的时候,不是传递的值。任何一方修改都会让SwiftUI的监视生效。
@GestureState能够让我们传递手势的状态,虽然使用@State也能实现,但@GestureState能让手势结束后我们回到最初的状态。
设置属性,设置zero意味着手势结束后,会回到最初的值。