我不太明白如何在类中正确存储订阅者,以便它们持续存在但不会阻止对象被取消初始化。这是对象不会取消初始化的示例:
import UIKit
import Combine
class Test {
public var name: String = ""
private var disposeBag: Set<AnyCancellable> = Set()
deinit {
print("deinit")
}
init(publisher: CurrentValueSubject<String, Never>) {
publisher.assign(to: \.name, on: self).store(in: &disposeBag)
}
}
let publisher = CurrentValueSubject<String, Never>("Test")
var test: Test? = Test(publisher: publisher)
test = nil
Run Code Online (Sandbox Code Playgroud)
当我assign用 a替换sink(在其中我正确声明[weak self])时,它实际上确实正确地进行了 deinit(可能是因为assign访问self的方式会导致问题)。
例如,如何在使用时防止强引用循环.assign?
谢谢
我一直在试验使用的 MVVM 模型,SwiftUI但有些东西我还不太明白。
SwiftUI使用@ObservableObject/@ObservedObject检测视图模型中触发body属性重新计算以更新视图的更改。
在 MVVM 模型中,这是视图和视图模型之间的通信。我不太明白的是模型和视图模型是如何通信的。
当模型发生变化时,视图模型应该如何知道这一点?我想到了手动使用新Combine框架在模型内部创建视图模型可以订阅的发布者。
但是,我创建了一个简单的示例,我认为该示例使这种方法非常乏味。有一个模型称为Game保存Game.Character对象数组。一个角色有一个strength可以改变的属性。
那么如果一个视图模型改变strength了一个角色的那个属性呢?为了检测这种变化,模型必须订阅游戏中的每一个角色(可能还有很多其他的东西)。是不是有点过分了?或者有很多发布者和订阅者是正常的吗?
还是我的示例没有正确遵循 MVVM?我的视图模型不应该将实际模型game作为属性吗?如果是这样,什么是更好的方法?
// My Model
class Game {
class Character {
let name: String
var strength: Int
init(name: String, strength: Int) {
self.name = name
self.strength = strength
}
}
var characters: [Character]
init(characters: [Character]) {
self.characters = characters
}
}
// ...
// My view model
class ViewModel: …Run Code Online (Sandbox Code Playgroud) 我有一个简单的例子。Trip我从数据库中获取所有对象:
import SwiftData
@Model
class Trip {
var name: String
}
func fetch() {
let container = ModelContainer(for: Trip.self)
let context = ModelContext(container)
let fetchDescriptor = FetchDescriptor<Trip>()
let trips = try! context.fetch(fetchDescriptor)
// Store it somewhere ...
}
Run Code Online (Sandbox Code Playgroud)
如何观察 trips 数组的变化?我知道数组中的各个对象是可观察的,并且当某些内容提交到数据库时会发生变化。但是,如果顺序发生变化,或者某些行程被删除或插入新行程怎么办?我找不到一种机制来通知这一点。
我发现的唯一方法是@Query在 SwiftUI 中使用新的属性包装器。但我想在单独的类中观察 SwiftUI 环境之外的变化。有没有办法做到这一点?
有没有一种方法可以轻松地重新创建ios 13的新共享表的模式表示样式?(起初,它只是中途显示,您可以向上滑动以使其成为“完整的”模态表)。我可以使用完全自定义的显示形式和内容来做到这一点,但是对于此行为是否有“本机” API,因此您不必不必使用自定义代码?
谢谢!
PDFKit在swift中使用,您可以使用PDFDocument打开pdf文件.这很简单,效果很好.但我正在构建一个适合我需求的自定义pdf查看器(适用于漫画书pdf),我遇到了一个问题.在查看器中,我不需要将整个pdf文件存储在内存中.我一次只需要几页.
此外,pdfs仅包含图像.没有文字或任何东西.
实例化a时PDFDocument,整个pdf数据被加载到内存中.如果你有非常庞大的pdf文件(超过1GB),这不是最佳的(并且可能会在某些设备上崩溃).据我所知,PDFKit中没有办法只加载pdf文档的部分内容.
我能做些什么吗?我还没有找到一个可以做到这一点的swift/obj-c库(虽然我真的不知道搜索它的正确关键字).
我的解决方法是预处理pdf并使用在.documents director(或类似)中将每个页面保存为图像FileManager.这将导致大量文件,但会解决内存问题.不过,我不确定我喜欢这种方法.
更新:
所以我做了@Prcela和@Sahil Manchanda提出的建议.它似乎现在正在发挥作用.
@yms:嗯,确实可能是个问题.当只有图像时,这甚至会发生吗?在pdf中没有任何其他内容.
@ Carpsen90:它们是本地的(保存在文档目录中).
编辑:我没有接受下面的答案,或给它赏金.这是自动的.它没有解决问题.它仍然将整个PDF加载到内存中!
所以我一直在尝试制作一个组件swiftUI,它允许您List在部分之间移动项目。
我准备了一个包含两个部分的示例:“第一列表”和“第二列表”。每当您点击一个项目时,它就会交换部分。这是一个屏幕截图:
当我点击“第一个列表:1”时,它会正确移动到第二部分:
但是,它的名称现在应该更改为“第二个列表:1”,因为我命名这些部分中的元素的方式(请参阅下面的代码)。所以这很奇怪。但它变得奇怪:
当我现在点击第二部分中的“第一个列表:1”时,会发生这种情况:
它没有正确交换回来。它只是被复制了,但这次重复的名称实际上是正确的。
考虑到下面的代码,我不明白这是怎么可能的。似乎以swiftUI某种方式重用该项目,即使它重新呈现视图?它似乎也重用了.onTapGesture闭包,因为应该将项目放回第一部分的方法实际上从未被调用过。
知道这里发生了什么吗?以下是该问题的完整示例:
import SwiftUI
import Combine
struct TestView: View {
@ObservedObject var viewModel: ViewModel
class ViewModel: ObservableObject {
let objectWillChange = PassthroughSubject<ViewModel,Never>()
public enum List {
case first
case second
}
public var first: [Int] = []
public var second: [Int] = []
public func swap(elementWithIdentifier identifier: Int, from list: List) {
switch list {
case .first:
self.first.removeAll(where: {$0 == identifier})
self.second.append(identifier)
case .second:
print("Called")
self.second.removeAll(where: …Run Code Online (Sandbox Code Playgroud) 我有一个List显示两个Views相同类型的。当您点击其中一个视图时,它们会通过动画改变高度。
但是,List嵌入的这些视图不会动画,这会导致丑陋的故障,因为List行的高度会立即更改,而该行内的实际视图是动画的:
我怎样才能制作List动画?我尝试向其添加.animation修饰符,但这没有任何作用。
我也不想将tapGesture视图移出。视图应该是自包含的,而不是依赖其他视图来控制它(我认为这就是 MVVM 的意义所在)
谢谢!
import SwiftUI
struct SubView: View {
@State var change: Bool = false
var body: some View {
Rectangle()
.frame(width: 200, height: change ? 300 : 200)
.foregroundColor(Color.red)
.onTapGesture {
withAnimation {
self.change.toggle()
}
}
}
}
struct Test: View {
var body: some View {
List {
SubView()
SubView()
}
}
}
struct Test_Previews: PreviewProvider {
static var previews: …Run Code Online (Sandbox Code Playgroud) 我观看了WWDC 2019会议``实践结合''(https://developer.apple.com/videos/play/wwdc2019/721/)。
在视频中,他们使用以下语法创建了发布者:
@Published var someName: String = ""
Run Code Online (Sandbox Code Playgroud)
他们这样做是为了someName成为出版商。但是,Xcode不喜欢这种语法,并给我一个错误:
未知属性“已发布
我不知道为什么。我正在macOS Catalina上使用Xcode 11 beta。
有任何想法吗?
所以我有一个自定义的UIView类
class MessageBox: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
createSubViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
createSubViews()
}
func createSubViews() {
let testView = UIView(frame: self.frame)
testView.backgroundColor = UIColor.brown
self.addSubview(testView)
}
}
Run Code Online (Sandbox Code Playgroud)
我在故事板中添加了一个UIView并给它一些约束:
从顶部100(superview),从左和右0,高度是180
但是当我运行应用程序时,我在代码中创建的棕色子视图是很大的.我self.frame在我的自定义视图中打印,结果表明框架是(0,0,1000,1000).但为什么?我设置约束,应该是这样的(0,0,deviceWith, 180).
我做错了什么?
编辑:这是我的故事板设置:
使用 iOS 模拟器时,我只需删除该应用程序并重新运行该应用程序即可重新开始。对于 macOS 应用程序,这是如何完成的?我找不到它。“DerivedData”内有一个项目文件夹,但删除它也会扰乱整个项目,我必须重新获取所有依赖项和内容。
谢谢!
swift ×9
ios ×5
combine ×3
swiftui ×3
macos ×1
pdf ×1
storyboard ×1
swift-data ×1
uiview ×1
xcode ×1