标签: combine

IOS 13 Combine Framework-@Published不起作用(“未知属性'Published'”)

我观看了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。

有任何想法吗?

ios swift combine

9
推荐指数
1
解决办法
1532
查看次数

在 Swift Combine 中使用 Publishers.debounce() 的正确语法是什么?

在 Apple 的 2019 年 WWDC 视频中Swift Combine in Practice,他们演示了使用debounce发布者来减慢消息速度。

return $username
  .debounce(for: 0.5, scheduler: RunLoop.main)
  .removeDuplicates()
  .eraseToAnyPublisher()
Run Code Online (Sandbox Code Playgroud)

但是,每当我尝试以类似的方式使用它时,都会出现以下错误:

无法使用类型为“(for:Double,调度程序:RunLoop)”的参数列表调用“debounce”

debounce()签名是:

public func debounce<S>(for dueTime: S.SchedulerTimeType.Stride, 
                          scheduler: S,
                            options: S.SchedulerOptions? = nil) -> 
                                    Publishers.Debounce<Self, S> where S : Scheduler
Run Code Online (Sandbox Code Playgroud)

SchedulerTimeType.Stride 似乎可以用数字初始化,但它对我不起作用,或者我对 Swift 泛型缺乏经验。

调用它的正确方法是什么?

编辑

重复这个问题...

目前,搜索诸如“组合”之类的通用词相当具有挑战性......

macOS 10.15,Xcode 11

swift swift5 combine

9
推荐指数
1
解决办法
5533
查看次数

SwiftUI:动画变化取决于@ObjectBinding

SwiftUI 具有使用 的隐式动画.animate()和使用 的显式动画.withAnimation()。但是,我无法弄清楚如何为图像更改设置动画:

struct ImageViewWidget : View {
  @ObjectBinding var imageLoader: ImageLoader

  init(imageURL: URL) {
    imageLoader = ImageLoader(imageURL: imageURL)
  }

  var body: some View {
    Image(uiImage:
      (imageLoader.data.count == 0) ? UIImage(named: "logo-old")! :  UIImage(data: imageLoader.data)!)
        .resizable()
        .cornerRadius(5)
        .frame(width: 120, height:120)
  }
}
Run Code Online (Sandbox Code Playgroud)

ImageuiImage参数传递的old-logo(预留),如果有中没有数据imageLoader(一BindableObject),并用正确的一个替换它一旦这样异步加载:

class ImageLoader : BindableObject {
  let didChange = PassthroughSubject<Data, Never>()

  var data = Data() {
    didSet {
      didChange.send(data)
    }
  }

  init(imageURL: URL) …
Run Code Online (Sandbox Code Playgroud)

swiftui combine

9
推荐指数
1
解决办法
2567
查看次数

使用Swift Combine创建Timer Publisher

我一直在看通过SwiftUI WWDC进行数据流。他们有一张带有示例代码的幻灯片,其中他们使用Timer发布者,该发布者连接到SwiftUI视图,并随时间更新UI。

我正在编写一些代码,在其中我想做完全相同的事情,但是无法弄清楚它PodcastPlayer.currentTimePublisher是如何实现的,然后将其连接到UI结构。我还看了所有关于Combine的视频。

我该如何实现?

示例代码:

struct PlayerView : View {
  let episode: Episode
  @State private var isPlaying: Bool = true
  @State private var currentTime: TimeInterval = 0.0

  var body: some View {
    VStack { // ...
      Text("\(playhead, formatter: currentTimeFormatter)")
    }
    .onReceive(PodcastPlayer.currentTimePublisher) { newCurrentTime in
      self.currentTime = newCurrentTime
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

publisher swift swiftui combine

9
推荐指数
3
解决办法
1355
查看次数

如何设置多个相同类型的 EnvironmentObjects

我发现了这个问题SwiftUI: Putting multiple BindableObjects into Envionment

答案说 environmentObject(ObservableObject) 返回修改后的视图,因此我可以为多个 environmentObject 创建调用链。

喜欢

let rootView = ContentView()
     .environmentObject(firstBindable)
     .environmentObject(secondBindable)
Run Code Online (Sandbox Code Playgroud)

我想知道如果 firstBindable 和 secondBindable 是相同类型的结果是什么。如何.environmentObject()知道什么是程序员打算在firstBindable和之间设置的 exec 值secondBindable

所以我测试了这个

  1. 我做了一个 ObservableObject 类
final class TempStr: ObservableObject {
    @Published var tmpStr = "temp"

    init(initStr: String) {
        tmpStr = initStr
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 从sceneDelegate 调用environmentObject
window.rootViewController
  = UIHostingController(rootView:
      TestView()
        .environmentObject(TempStr(initStr: "1st")) 
        .environmentObject(TempStr(initStr: "2nd"))
Run Code Online (Sandbox Code Playgroud)
  1. 并使用视图中的值
struct TestView: View {
  @EnvironmentObject var tmp1: TempStr
  @EnvironmentObject var tmp2: TempStr

   var body: some …
Run Code Online (Sandbox Code Playgroud)

publish observable swiftui combine

9
推荐指数
1
解决办法
2006
查看次数

NSManagedObject 更改不会触发 objectWillChange

我有一个核心数据模型,其中一个实体生成到 class 中Task。我正在尝试objectWillChangeNSManagedObject发送(自动,无需手动工作)中获取合并发布者,但它不会。任务实体有一个name属性。

let task = Task(context: container.viewContext)

let taskSubscription = task.objectWillChange.sink(receiveValue: { _ in
    print("Task changed")
})

task.name = "Foo"              // WILL NOT trigger
Run Code Online (Sandbox Code Playgroud)

如果我手动调用发送,订阅将起作用:

task.objectWillChange.send()   // Will trigger
Run Code Online (Sandbox Code Playgroud)

如果我用一个 simple 替换ObservableObject它,它将按预期工作:

class DummyTask: ObservableObject {
    @Published var name: String?
}
Run Code Online (Sandbox Code Playgroud)
let dummy = DummyTask()
let dummySubscription = dummy.objectWillChange.sink(receiveValue: { _ in
    print("Dummy changed")
})

dummy.name = "Foo"              // Will trigger
dummy.objectWillChange.send()   // Will trigger
Run Code Online (Sandbox Code Playgroud)

NSManagedObject 被窃听了吗?我应该如何观察通用实体对象的变化?我应该如何让 SwiftUI 看到它们? …

core-data swift swiftui combine

9
推荐指数
2
解决办法
2557
查看次数

Swift Combine 替代 Rx Observable.create

我有一些使用 RxSwift 构建的代码,我正在尝试将其转换为使用 Apple 的 Combine 框架。

一种非常常见的模式是使用Observable.create一次性可观察对象(通常是网络请求)。像这样的东西:

func loadWidgets() -> Observable<[Widget]> {
  return Observable.create { observer in
    // start the request when someone subscribes
    let loadTask = WidgetLoader.request("allWidgets", completion: { widgets in
      // publish result on success
      observer.onNext(widgets)
      observer.onComplete()
    }, error: { error in
      // publish error on failure
      observer.onError()
    })
    // allow cancellation
    return Disposable {
      loadTask.cancel()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试将其映射到结合,但我一直无法弄清楚。我能得到的最接近的是使用 Future 来做这样的事情:

func loadWidgets() -> AnyPublisher<[Widget], Error> {
  return Future<[Widget], Error> { resolve in
    // …
Run Code Online (Sandbox Code Playgroud)

swift combine

9
推荐指数
1
解决办法
2580
查看次数

在主线程上使用@Published 值?

有没有办法指定 count 应该只在主线程上发布?我看过一些讨论使用 设置发布者的文档receive(on:),但在这种情况下,@Publisher包装器隐藏了该逻辑。

import SwiftUI
import Combine

class MyCounter: ObservableObject {
  @Published var count = 0

  public static let shared = MyCounter()
  
  private init() { }
}

struct ContentView: View {
    @ObservedObject var state = MyCounter.shared
    var body: some View {
        return VStack {
            Text("Current count: \(state.count)")
            Button(action: increment) {
                HStack(alignment: .center) {
                    Text("Increment")
                        .foregroundColor(Color.white)
                        .bold()
                }
            }
        }
    }
    
    private func increment() {
        NetworkUtils.count()
    }
}

public class NetworkUtils {

    public static …
Run Code Online (Sandbox Code Playgroud)

swift swiftui combine

9
推荐指数
2
解决办法
2612
查看次数

迅速。结合。有没有办法在重试时多次调用发布者块?

当使用 Swift/Combine 中的 retry() 发生某些错误时,我想多次发出网络请求。发布者内部的块只被调用一次,这意味着当发生错误时,对真正的应用程序只有一个请求。我的代码是:

import UIKit
import Combine
import PlaygroundSupport

enum TestFailureCondition: Error {
    case invalidServerResponse
}

var backgroundQueue: DispatchQueue = DispatchQueue(label: "backgroundQueue")

var failPublisher: AnyPublisher<(Data, URLResponse), Error> {
    Future<(Data, URLResponse), Error> { promise in
        print("Attempt to call")
        backgroundQueue.asyncAfter(deadline: .now() + Double.random(in: 1..<3)) {
            promise(.failure(TestFailureCondition.invalidServerResponse))
        }
    }
    .eraseToAnyPublisher()
}

let cancellable = failPublisher
.print("(1)>")
.retry(3)
.print("(2)>")
.sink(receiveCompletion: { fini in
    print(" ** .sink() received the completion:", String(describing: fini))


    PlaygroundPage.current.finishExecution()
}, receiveValue: { stringValue in
    print(" ** .sink() received \(stringValue)") …
Run Code Online (Sandbox Code Playgroud)

swift combine

9
推荐指数
2
解决办法
2889
查看次数

将异步方法转换为组合

我正试图将我的头围绕在 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)

swift combine

8
推荐指数
1
解决办法
1477
查看次数

标签 统计

combine ×10

swift ×8

swiftui ×5

core-data ×1

ios ×1

observable ×1

publish ×1

publisher ×1

swift5 ×1