我正试图将我的头围绕在 Combine 上。
这是我想转换为Combine 的方法,以便它返回AnyPublisher。
func getToken(completion: @escaping (Result<String, Error>) -> Void) {
dispatchQueue.async {
do {
if let localEncryptedToken = try self.readTokenFromKeychain() {
let decryptedToken = try self.tokenCryptoHelper.decrypt(encryptedToken: localEncryptedToken)
DispatchQueue.main.async {
completion(.success(decryptedToken))
}
} else {
self.fetchToken(completion: completion)
}
} catch {
DispatchQueue.main.async {
completion(.failure(error))
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
整个过程在单独的调度队列上执行,因为从 Keychain 读取和解密可能很慢。
我第一次尝试拥抱结合
func getToken() -> AnyPublisher<String, Error> {
do {
if let localEncryptedToken = try readTokenFromKeychain() {
let decryptedToken = try tokenCryptoHelper.decrypt(encryptedToken: localEncryptedToken)
return Result.success(decryptedToken).publisher.eraseToAnyPublisher()
} else { …Run Code Online (Sandbox Code Playgroud) 在使用 SwiftUI 和 Combine 时,您将如何检测 Datepicker 的值变化?每当移动日期选择器轮时,我都需要调用一个方法,以更新文本和滑块。
我一直在寻找特定的方法来识别值的变化(使用 UIKit 可以将一个动作与一个事件相关联),但显然我没有在文档中找到任何有用的东西(我已经尝试过 onTapGesture 方法,但这不是我想要什么,因为它强制用户点击选择器来更新其他视图,而我希望在用户移动轮子时自动更新)。
import SwiftUI
struct ContentView: View {
private var calendar = Calendar.current
@State private var date = Date()
@State private var weekOfYear = Double(Calendar.current.component(.weekOfYear, from: Date()) )
@State private var lastWeekOfThisYear = 53.0
@State private var weekDay: String = { () -> String in
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE"
let weekDay = dateFormatter.string(from: Date())
return weekDay
}()
var body: some View {
VStack {
// Date Picker …Run Code Online (Sandbox Code Playgroud) 尝试发出网络请求时,出现错误
finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled"
Run Code Online (Sandbox Code Playgroud)
如果我使用它URLSession.shared.dataTask而不是URLSession.shared.dataTaskPublisher它将在 IOS 13.3 上工作。
这是我的代码:
return URLSession.shared.dataTaskPublisher(for : request).map{ a in
return a.data
}
.decode(type: MyResponse.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
Run Code Online (Sandbox Code Playgroud)
此代码适用于 IOS 13.2.3。
我正在为我的 API 请求使用 Swift Combine。现在我面临的情况是,我想要将 4 个以上的并行请求压缩在一起。在我使用 Zip4() 运算符将 4 个请求压缩在一起之前。我可以想象您分多个步骤进行压缩,但我不知道如何为其编写 receiveValue。
这是我当前代码的简化,包含 4 个并行请求:
Publishers.Zip4(request1, request2, request3, request4)
.sink(receiveCompletion: { completion in
// completion code if all 4 requests completed
}, receiveValue: { request1Response, request2Response, request3Response, request4Response in
// do something with request1Response
// do something with request2Response
// do something with request3Response
// do something with request4Response
}
)
.store(in: &state.subscriptions)
Run Code Online (Sandbox Code Playgroud) 如何转换Just<[Int]>为AnyPublisher<[Int], Error>. 当我使用eraseToAnyPublisher()类型是AnyPublisher<[Int], Never>这与AnyPublisher<[Int], Error>
例如,我有一个简单的函数,我想临时模拟它
func getAllIds() -> AnyPublisher<[Int], Error> {
return Just<[Int]>([]).eraseToAnyPublisher()
}
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
在尝试使用Combine 分配值时,我看到了一些我不太理解的结构与类行为。
代码:
import Foundation
import Combine
struct Passengers {
var women = 0
var men = 0
}
class Controller {
@Published var passengers = Passengers()
var cancellables = Set<AnyCancellable>()
let minusButtonTapPublisher: AnyPublisher<Void, Never>
init() {
// Of course the real code has a real publisher for button taps :)
minusButtonTapPublisher = Empty<Void, Never>().eraseToAnyPublisher()
// Works fine:
minusButtonTapPublisher
.map { self.passengers.women - 1 }
.sink { [weak self] value in
self?.passengers.women = value
}.store(in: &cancellables)
// Doesn't work:
minusButtonTapPublisher …Run Code Online (Sandbox Code Playgroud) 组合订阅示例代码片段全部将生成的订阅存储到集合subscriptions中
private var subscriptions = Set<AnyCancellable>()
Run Code Online (Sandbox Code Playgroud)
为什么我们需要这样做?
future
.sink(receiveCompletion: { print($0) }, receiveValue: { print($0) })
.store(in: &subscriptions)
Run Code Online (Sandbox Code Playgroud) 让\xe2\x80\x99s 假设您正在 AnyCancellable 上使用内置.store(in:)方法,如下所示:
private var subscriptions = Set<AnyCancellable>()\n\nlet newPhotos = photos.selectedPhotos\nnewPhotos\n .map { [unowned self] newImage in\n return self.images.value + [newImage]\n }\n .assign(to: \\.value, on: images)\n .store(in: &subscriptions)\nRun Code Online (Sandbox Code Playgroud)\n如果您有一个经常执行此操作的应用程序 - 发布商完成后这些内容是否会被删除?
\n另外,如果我决定采用这种方法:
\nprivate var newPhotosSubscription: AnyCancellable?\n\nself.newPhotosSubscription = newPhotos\n .map { [unowned self] newImage in\n self.images.value + [newImage]\n }\n .assign(to: \\.value, on: images)\nRun Code Online (Sandbox Code Playgroud)\n每次我再次调用该方法时,它都会覆盖 AnyCancellable,前一个会发生什么?它在被释放之前是否仍然完成?
\n当我有一个嵌套的 ObservedObject 时,嵌套对象的已发布属性的更改不会更新 UI,直到父对象发生某些情况。这是一个功能、一个错误(在 SwiftUI 中)还是我的代码中的一个错误?
这是一个简化的示例。单击父级的开/关按钮会立即更新 UI,但单击子级的开/关按钮不会更新,直到父级更新为止。
我正在运行 Xcode 12.5.1。
import SwiftUI
class NestedObject: NSObject, ObservableObject {
@Published var flag = false
}
class StateObject: NSObject, ObservableObject {
@Published var flag = false
@Published var nestedState = NestedObject()
}
struct ContentView: View {
@ObservedObject var state = StateObject()
var body: some View {
VStack {
HStack {
Text("Parent:")
Button(action: {
state.flag.toggle()
}, label: {
Text(state.flag ? "On" : "Off")
})
}
HStack {
Text("Child:")
Button(action: {
state.nestedState.flag.toggle()
}, label: …Run Code Online (Sandbox Code Playgroud) 这是我第一次使用 AppKit 和NSTableView. 它由NSFetchedResultsController核心数据支持。当数据集发生更改时,Notification将发送:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
guard let links = self.fetchedResultsController.fetchedObjects else {
return
}
if self.viewContext.hasChanges {
try? self.viewContext.save()
}
self._links = links
NotificationCenter.default.post(name: .reloadLinkList, object: nil)
}
Run Code Online (Sandbox Code Playgroud)
NotificationCenter.default.publisher(for: .reloadLinkList).receive(on: RunLoop.main).sink { notification in
self.list.tableView.reloadData()
self.list.linksModel.selectedRows = IndexSet([])
}
.store(in: &cancellables)
Run Code Online (Sandbox Code Playgroud)
这对于插入和更新数据非常有用。当我尝试删除某些内容时,我得到:
Thread 1: Fatal error: UnsafeRawBufferPointer with negative count
Run Code Online (Sandbox Code Playgroud)
删除选定对象的代码如下:
Thread 1: Fatal error: UnsafeRawBufferPointer with negative count …Run Code Online (Sandbox Code Playgroud)