Skip to content

Latest commit

 

History

History
281 lines (174 loc) · 9.95 KB

说明.md

File metadata and controls

281 lines (174 loc) · 9.95 KB

RxStudy

RxSwift/RxCocoa框架的学习

更新2021年5月25日

这个项目建立的时间我查看了一下git的提交记录,2019年1月29日。

过了2年了才重新开始RxSwift的学习,我不得不说对我而言Rx还是很难,可能是我没有理解。

跑去学了Flutter和简单的Vue入门,说实话Vue的学习成本是最低的,因为它的MVVM框架基本上已经好了,你不需要做太多的操作,开箱即用。

Flutter的学习曲线稍微难一点,但是学会了Provider之后,基本也算是在MVVM上路。

反观Rx的学习曲线真的是陡峭啊,虽然我理解Oberveral其实就是异步的stream,但是使用起来的时候还是一脸懵逼,因为它不过智能简单,需要理解大量非原生的API。

如果你要说为啥不直接上Combine,我只是想说Rx学了,Combine还会难么?

SwiftUI+Combine联合起来才能展现威力,不过在苹果这一侧,一个好的响应式和状态管理都还不够好,虽然Rx有些框架已经在向大前端的实现了,可惜的时候原生的支持不够好的,学习成本也太高了。

这个可能是我第一个Swift的MVVM项目,依旧撸的玩安卓的api。

我已经写了Flutter和uni-app版本,所以Swift版本更看重的逻辑与RxSwift的理解。

曾经的我更看重在单个UI上的编写与实现,现在经常想的是这个有没有现成的轮子可以,更偏向于思路与思考。我不是说UI不需要思考,如果有好用的轮子何乐而不为呢?

能用OC桥接过来的库,必然有它的独特性与通用性,MJRefresh与MB、SV真香。

更新2021年7月28日

MBProgressHUD全部替换为SVProgressHUD。

黑暗模式适配完成。

Flutter版wanandroid客户端

项目地址

uni-app版wanandroid客户端

项目地址

Xcode新版的代码块

代码块

最近的出现的bug

[TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window. Table view: <UITableView: 0x14c864c00; frame = (-207 -368; 414 736); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x28028cea0>; layer = <CALayer: 0x280cdf420>; contentOffset: {0, 0}; contentSize: {414, 0}; adjustedContentInset: {0, 0, 44, 0}; dataSource: <RxCocoa.RxTableViewDataSourceProxy: 0x2828e4060>>

我在Stack Overflow看了一下,大概意思就是我没有在主线程进行页面布局

Stack Overflow

然后我把BaseTableViewController => viewDidLoad => setupTableView => 简单布局

DispatchQueue.main.async {
    
}

我这个包裹就可以,我实在没明白为什么

Release模式下编译错误

2021年10月13日,经常尝试跑Release模式,直接报错了,目前还没有时间考虑这个问题。

remark: Incremental compilation has been disabled: it is not compatible with whole module optimization
Command CompileSwiftSources failed with a nonzero exit code

已经解决:

链接在下方: https://stackoverflow.com/questions/52387452/command-compileswift-failed-with-a-nonzero-exit-code-in-xcode-10

使用的方案是下面这种:

我搜索了在pod中使用了CommonCrypto的框架,发现是Kingfisher,然后我先注释掉了Kingfisher,进行pod install操作,然后在进行pod install --repo-update就好了。

Optimize Object Lifetimes

在看了这篇文章之后,我开启了Xcode13中有关Swift中生命周期优化的配置。

Xcode13对Swift对象生命周期的优化

在Xcode13中新建一个.js文件,找不到

我新建了一个appStore.js文件,但是R函数编译,或者使用原生的Boundle.main.url的方法都没有找到它。

后来我就在想,是不是工程根本没有添加进来。

然后我在TARGETS → Build Phases→Copy Boundle Resources列表中果然没有。

最后自己手动添加后,才正常。

准备使用路由工具的,后来看了一下就没有使用

我本来打算在这个项目里面使用第三方路由工具的,然后我跑去看了一下我整个项目中使用push和pop方法的次数。

push 7次

pop 2次

对于一个逻辑跳转简单的工程,使用复杂的路由工具反而不合时宜,于是就放弃了。

打算通过KVO来监听系统切换Light或者Dark模式,然后想试试RxSwift的版本

class Person: NSObject {
    var name: String = ""
    var height: CGFloat = 1.80
    var address: String = ""
}

普通版本

var model = Person()
var observer: NSKeyValueObservation?

observer = model.observe(\Person.name, options: [.old, .new]) { (model, change) in
  if let old = change.oldValue {
    print(old)
  }
  if let new = change.newValue {
    print(new) 
  }
}

// 修改model的值
model.name = "season"

最后别忘了删除观察者

model.removeObserver(self, forKeyPath: "name")

Rx版本:

let p1 = Person()
p1.name = "flion"
p1.height = 190
p1.address = "china"
p1.rx.observe(String.self, "address").subscribe(onNext: { value in
    print("new address is \(value)")
}).disposed(by: disposeBag)

p1.address = "usa"

使用rx.observe同样存在着原生KVO所面临的问题,即rx.observe只能作用于NSObject子类的class类型,而不能作用于struct和enum。所以为了能更通用一点,再继续看下面的方法吧。

struct Person {
    var name: String = ""
    var height: CGFloat = 180
    var address: String = "" {
        didSet {
            addressSubject.onNext(address)
        }
    }
    var addressSubject = PublishSubject<String>()
}

let p2 = Person()
p2.name = "flion"
p2.height = 190
p2.address = "china"
p2.addressSubject.asObservable().subscribe(onNext: { value in
    print("new address is \(value)")
}).dispose(by: disposeBag)

p2.address = "usa"

Relay基本同理,详细见这篇文章:

https://www.jianshu.com/p/5b402cd97330

一个GitHub上面的功能尝试

Github Actions 免费构建 iOS 包

RxSwift6.5出现的bug

在更新到RxSwift6.5后,发现WebViewController的收藏状态有异常,

明明isContainsRelay我优化成为PublishRelay类型,并且只做了一次isContainsRelay.accept操作,但是subscribe却走了两次,而且没有收藏,第二次的值确实true.

我回滚到RxSwift5.1版本,发现是好的,我觉得是RxSwift向上升级,导致的bug

isContainsRelay.subscribe { [weak self] event in
	switch event {

	case .next(let value):
		self?.collectionButton.isSelected = value
	default:
		break
	}
}.disposed(by: rx.disposeBag)

最后发现,是这个页面的viewModel.output.collectRelay与vm.outputs.unCollectRelay中这两个relay使用是BehaviorRelay类型.

结果就进行了默认值绑定,出了异常,奇怪的是RxSwift5.0是好的,但是RxSwift6.5是有问题的.

只能认为,5.0的时候先默认,然后在用进行是否登录的判断处理,而6.5是先进行是否登录的判断处理,再默认,结果最后绑定的是默认值

R.swift升级文档

https://github.com/mac-cain13/R.swift/blob/master/Documentation/Migration.md

Swift-DocC

  • 这里设置为Yes

Snip20220909_32

  • 进行编译

  • Help打开

  • 进行导出

    image-20220909120210982

关于setupUI与binding

按照我后面对于工程的写法,一般情况下会将页面布局写在setupUI中,而viewModel对于数据对UI的绑定写在binding中,目前对于整个RxStudy工程正在进行代码的CodeReview,已完成绝大部分符合要求的思路。

关于SwiftLint

文档:https://github.com/realm/SwiftLint/blob/main/README_CN.md

使用的是Homebrew全局使用的SwiftLint,如果需要通过Cocopods安装SwiftLint,请根据官方文档进行集成,如果不想管理这里,直接删除Build Phase中的SwiftLint Run Script。

关于PrivacyInfo.xcprivacy

update_privacy_info.py:一个自动化脚本用于生成与检查PrivacyInfo.xcprivacy

missing-api-declaration-for-accessing-userdefaults-timestamps-other-apis

通过使用根目录下的update_privacy_info.py可以进行排查与生成。

RxStudy git:(develop) ✗ python3 update_privacy_info.py /Users/season/Documents/Swift\ Git/RxStudy

关于periphery

periphery

这个库主要是用于检查无用代码的,我的安装方式是通过Homebrew进行全局安装。

然后在项目根目录执行,进行配置即可,配置完成后会生成一个.periphery.yml文件,其实和SwiftLint很类似。

periphery scan --setup  

通过pod集成如何操作我目前还不会太,全局配置扫描出来的结果还算不错。

后面就直接使用

periphery scan