干货 | 深入浅出Apple响应式框架Combine

iOS进阶1-combine Combine 是 Apple 在 WWDC 2019 上推出的一个声明式编程框架,它基于响应式编程 (Reactive Programming)思想,用于处理应用中的异步事件流,比如网络请求、数据存储、UI 交互、定时器等。其核心目标是简化异步代码的编写、提高可读性和可维护性,并提供一种统一的方式来处理各种事件流。Combine 是 iOS 开发中处理异步事件和状态管理的强大工具,其核心是 “发布者 - 订阅者 - 运算符” 模型。 阅读详情

作者简介

 

青花瓷的平方,携程技术专家,主要从事无线开发,负责携程支付iOS相关开发工作。

一、引言

Combine.framework 是Apple在2019 WWDC 上基于Swift推出的函数响应框架(Functional Reactive Programming),支持Apple全平台的操作系统(iOS13+,macOS 10.15+等)。函数式响应框架无论在哪个平台早已流行泛滥,开源的Rx更是实现了各种语言的响应式编程框架。Apple在这个时候推出响应式框架,无疑是对自己护城河的进一步巩固。事实上SwiftUI的数据驱动就是依赖Combine。

本文将深入浅出地介绍Combine的基本概念和原理,然后通过具体demo详细阐述其在实际编码中的应用。


二、什么是Combine

Combine is Swift declarative framework for processing values over time

Combine 为处理随着时间变化的值的一种声明式框架。Combine 作用是将异步事件通过组合事件处理操作符进行自定义处理。关注如何处理变化的值,正是响应式编程的核心。

Combine可以概述为一种声明式的函数响应式编程,简洁用下图表示:

通过此图,我们可以总结Combine是什么:

Combine = Publishers + Operators + Subscribers


2.1 Publishers

Publisher sends sequences of values over time to one or more Subscribers.

发布者(Publisher)随着时间变化发送一系列的值给一个或者多个订阅者(Subscriber)。

一个发布者可以发布一个value,Value的类型为Output,有两种状态:成功/失败。成功会发送Value,失败就会产生Failure,Failure的类型为Error。当然如果一个发布者永远不失败,那么失败就是Never类型。

Combine内置的Publisher有Just, Future, Deferred, Empty, Fail, Record, Published以及PassthroughSubject和CurrentValueSubject。Published实际上是用propertyWrapper封装的Publisher,它可以将任意一个变量封装成一个Publisher,并通过projectedValue(影子变量)轻松实现MVVM,本文将在后续介绍。

2.2 Subscribers

Subscriber receives values from a publisher.

订阅者(Subscriber)接收发布者发送的Value。订阅者遵循的协议如下:

订阅者接受一个Input类型的Value以及接收到事件失败的类型Failure。protocol中的三个receive方法描述了订阅三种不同的生命周期,本文会在后续2.5介绍。

Publisher发布者协议中有两个通用类型参数Output和Failure。而Subscriber订阅者接受一个Input类型的Value或者接收到事件已经发送成功或者失败。既然订阅者和发布者都有了,接下来的关键是如何连接他们,连接他们的是Subscribtion(订阅),我们将在2.5中详细介绍。

使用sink方法和assign方法将在Combine内部自动创建subcribtion连接发布者和订阅者。Publisher发布者协议中有两个通用类型参数Output和Failure,而Subscriber订阅者接收发布者产生的Output和Failure,因为发布者和订阅者是互相协作的,所以一个匹配的发布者和订阅者会有Output==Input和Failure == Failure,如果不匹配,编译器会自动报错提示我们。

Combine内置了两种Subscribers,分别是Subscribers.Sink和Subscriber.Assign。简单举例说明:

注释1中我们创建了List,并使用内置的Publishers.Sequence<[Int], Never>创建了Publisher,其中Int是输入参数Output,明显是数组中的单个元素,并且指定了失败类型为Never。然后我们创了subscriber,指定input为Int,Failure为Never。然后通过subscriber方法连接他们,subcriber方法会在内部创建subcription连接Publisher和Subscriber。最终输出如下:

receiveValue:1 receiveValue:2 receiveValue:3 receiveValue:4 receiveValue:5 receiveValue:6 finished

得益于Swift的Extension,我们可以将上述创建的subscriber包裹到Publisher的Extension中,所以就有了注释2的简化版。进一步,我们可以拓展序列的Extension,将publisher封装到Sequence的扩展中,所以才有最终简化版方法注释3。


2.3 Subject

Subject主题是一种特殊的发布者,它可以自己主动传送Value到Combine事件流中,接口如下:

Combine内置了两种Subject,分别是PassthrougSubject和CurrentValueSubject,他们的含义都很明确。这里我们通过举例来说明PassthrougSubject:

上述代码中我们创建subject对象,指定Output为String,Failure为ExampleError。然后通过sink产生订阅者连接,sink方法返回的是Anycancellabel对象,它表示一个发布者和订阅者的链接可取消,通过store方法将其保存在外部变量setList数组中,这样能保证订阅者不会被释放。最终输出结果如下:

Subscriber received value: Hello! Subscriber received value: Hello Again! failure(CombineTest2.ExampleError.somethingWentWrong)

从输出中可以看到一旦一个事件流完成(completion)或者遇到Error后,后续再发送其他的值,由于此时事件流已经结束,所以输出结果中不会再有后续的send的Value。


2.4 Operators

响应式编程的核心其实是Publishers各种转换,为什么要有操作符?因为任何一个事件流中,往往最初的对象和我们最后产生的对象并不一致,这时候就要通过Operator来转换输入的对象。Combine中的Operator是将一个Publisher作为输入对象,通过operator产生另一个Publisher。

Combine中的各种operators是定义在Publisher的各种Extension中。在各自的扩展中实现了内置的classes或者structures。举例来说,map(:)操作符返回的对象是Publishers.Map对象。Apple目前内置了50多种Operators,尽管这样,它仍然比Rxswift少,这里有一份Combine和RxSwift的操作符对比RxSwift to Combine Cheatsheet。我们列举几种简单的如下图:

我们通过URLSession内置的dataPublisher发送网络请求解析来说明用法,目的是为了说明Combine中的异步API以及在异步API中如何使用Operator。代码示例如下图:

1)我们定义了常见的网络请求的错误类型;

2)UserResponse返回的是服务端的json数据Model;

3)判断URL是否有误,如果异常,返回PassthroughSubject生成的订阅者,发送unsupportUrl的Failure告知外部事件流结束;

4)tryMap的Input类型是dataPublisher返回的元组(data: Data, response: URLResponse),我们判断http的statusCode是否异常,如果异常直接thorw错误,否则将元组的第一个元素data返回,所以对应的Output为Data,Failure为CustomAPIError;

5)通过decode操作符将data转换为UserResponse,decode的失败Failure类型为Error;

6)处理tryMap和decode产生的Error,将其全部转换为CustomAPIError;

7)最后通过earseToAnyPublisher将内部产生的Publisher类型擦除,因为外部关心的是Publisher携带的UserResponse和CustomAPIError;

8)最终调用sink方法可以轻松的接送服务返回的数据。


2.5 生命周期

在2.2中我们已经说明了连接Publisher/Subscriber实际是通过一个中介对象Subscription。完成的流程如下图:

  • 1-3,当一个订阅者Subscriber创建和绑定到发布者Publisher,订阅者Publisher将创建一个Subscription对象,并将subscriber的引用发给Subscription,这是时序图中的步骤1-3。

  • 4,这时候订阅者Subscriber和发布者Publisher已经通过subscription绑定了,订阅者Subscriber就可以通过request(_ demand:)方法获取它想要多少个Value,demand参数实际上是一个Int包裹值,类型包括:

Subscribers.Demand.none Subscribers.Demand.unlimited Subscribers.Demand.max(Int)

当我们通过Publisher的sink方法创建subscription时候,实际request的参数是.unlimited,因为它想接收发布者Publisher发送的所有values。大多情况这是我们想要的,但是某些情况如果想要限制订阅者的请求次数,那么就可以通过定义具体的max携带的Int值,比如:

上图中我们自定义了IntSubscriber,在receive(subscription:)方法中最多请求接收2次Value,所以在console会输出如下:

Received subscription Received input:0 Received input:1

最终我们只接收到2次Input,由此可见Demand决定了订阅者和Subscription的生命周期。

  • 5,收到订阅者Subscriber的请求后,subscription通过发布者Publisher发送Value给订阅者Subscriber;

  • 6-7,subscription根据Demand的值来提交value,通过调用receive(_:)方法发送value,直到到达发送次数Demand的最大值;

  • 8,订阅者接收subscription发送的value,作为响应,它将返回一个新的Demand,注意到demand会根据先前已发送的demand进行相加,所以demand会保持至少不会减少;

  • 一旦新的Demand被subscription接收到,subscription又会根据demand重新来提交value,因此整个6-8过程是循环过程,一直到接收到completion或者Failure整个事件流才完全结束,这就是时序图中的9-10。


2.6 Debugging

响应式编程的最大痛点就是出现bug难以排查问题,但Apple设计的API通常简洁好用且方便调试。Apple提供了print()和HandleEvents()两种API来控制输出,方便开发者调试。

通过举例来说明:

我们将数组[1,2,3,4]的publisher过滤数组中的奇数,然后通过map将转换成平方,在此通过map转换成String,最终终端输出如下:

receive subscription: ([1, 2, 3, 4]) //1 request unlimited //2 receive value: (1) //3 request max: (1) (synchronous) //4 receive value: (2) //5 receiveValue=EventNumber=4 //6 receive value: (3) request max: (1) (synchronous) receive value: (4) receiveValue=EventNumber=16 receive finished completion=finished

注释1是我们通过数组最终转换的Publisher.Map通过receive方法连接订阅者AnySubscriber,然后创建subscription连接他们,紧接着subscriber通过request(:)方法获取需要知道请求多少个value,这里是无限次。

然后subscription提交value,subscriber通过receive(:)方法接收value:1,并返回响应Demand.max(1)。这里涉及到Filter的实现问题,由于1不是偶数,因为不满足我们的条件,在Combine的Publishers.Filter中会在receive(_:)方法中将不满足过滤条件的value返回max(1),从而保证事件流下一次执行。注释5接收到value:2,满足fliter然后进行map转换提交value,一直到事件complete完成,整个事件流才结束。这里佐证了我们在2.5时序图描述是正确的。

上述print()函数也可以替换成HandleEvents(),他们没有太大的区别,但是能给我们提供更好的输入以及提供手动设置断点。

输出如下:

receiveRequest:unlimited receiveSubscription:[1, 2, 3, 4] receiveOutput:1 receiveRequest:max(1) receiveOutput:2 receiveOutput:3 receiveRequest:max(1) receiveOutput:4 receiveCompletion:finished

此外还有breakpointOnError()和breakpoint(),本文限于长度不在累述,详情可参考Apple官方文档。


三、实战

3.1 自定义Publishers和Subscribers

iOS13系统内置了诸如KVO,Notification,URLSession,Timer的Publisher,所以大部分场景开发者不需要自定义的Publisher,但某些场景也有特定需求。UIKit本身自带了很多UI控件的事件,但iOS系统本身确没有给出内置的publisher,为此我们需要自定义UIControl的Publisher。

3.1.1 自定义Subscription

在创建Plublisher之前,我们先创建Subscrption,因为Subscription是连接发布者和订阅者的中介者,没有它Combine事件流无法驱动。

我们定义了UIControlSubscription:

1)构造器带有三个参数:分别是subscriber,control,以及Control的事件类型。我们保存subcriber,是因为在接下来的点击事件中,要让subcriber接收Value。因为点击事件不会有失败类型,所以限制Failure类型为Never;

2)实现cancel方法,以便于Combine能正确的释放资源;

3)注意到Subscription在初始化时候回调用receive(:)方法,系统内置的Subscriber.Sink在receive方法中会调用request(.unlimited),这里不再request填充任何代码,是因为我们只想当点击事件发生就立即处理,无论当前的请求次数是多少。一旦用户出发了点击事件,就会执行eventHandler方法,订阅者subcriber就会立即接收我们UIControl。


3.1.2 自定义Publisher

当UIControl的事件发生时,需要将UIControl本身传递出去。我们定义UIControlPublisher代码如下:

1)UIControlPublisher的Output传递为UIControl本身,Failure为Never。

2)在构造器中,除了传递UIControl,还将事件UIControl.Event传递进去,因为我们想要处理不同的UI事件。

3)receive方法是将订阅者连接到发布者上,我们内部创建在3.1.1中定义的UIControlSubscription,然后调用subscriber的receive方法向Publisher请求接收Control。


3.1.3 使用UIControlPublisher

我们在UIControlPublisher中使用了泛型,这样在拓展UIControl子控件时候就可以无需转换,方便地直接使用。拓展常见的UI事件的Publisher如下:

1)使用Extension集成了publisher的通用方法,这样它的所有子控件都可以快速使用该方法。

2)除了通用的publisher,我们还使用Extension扩展了UITextFiled输入框监听文字可变的Publisher,以及UISwitch开关状态的Publisher。


3.1.4 补充说明

我们自定义了UIControlPublisher,限于篇幅不会再定义其他诸如异步事件处理的Publisher。虽然Combine本身是闭源的,但Combine在Foundation层的代码确是开源的,有兴趣的读者可以参考Swift源码中Publishers+URLSession.swift和Publishers+NotificationCenter.swift进一步了解Publisher和Subscriber是如何协同工作的原理。


3.2 实战

实现一个简单登录注册的UI,如下所示:

界面很简单,就是用户名,密码,确认密码三个输入框以及同意隐私协议开关按钮和注册按钮。来给定一个简单的验证规则:

1)当用户输入登录名称大于等于6位;

2)密码和确认密码相等并且至少为6位;

3)用户同意隐私协议;

同时满足上述三个条件时注册按钮才点击可用,我们使用Combine来实现注册校验逻辑。


3.2.1 ViewModel

用Combine来实现MVVM,首先显示RegisterViewModel,如下:

1)注意到我们使用了Property Wrapper的Published来生成一个Publisher,Published包装任意一个变量成为Publisher,并且可以使用$符号表示其自身实际的Publisher。分别定义用户名username,密码password,二次确认密码confirmPwd,以及同意协议accept的Publisher。

2)定义validToRegisterPublisher为注册按钮可点击的Publisher为只读属性,内部使用CombineLatest操作符来生成新的Publisher,CombineLatest会依赖发布者产生的最新value值,然后通过map转换我们要求的验证规则是否合法,返回Bool类型,true表示注册按钮可点击。最后在使用eraseToAnyPublisher()来擦除产生的发布者类型,因为使用者最终只关心发布者携带的value值的类型。


3.2.2 Bind ViewModel

下面是在VC中具体bind ViewModel的示例:

1)我们实现了bindView()方法,该方法将UI控件通过在3.1中封装的自定义UIControlPublisher实现UI控件的事件绑定,并且将Publisher产生的值绑定到ViewModel中对应的Publisher中。

2)调用系统内置的assign方法将validToRegisterPublisher产生的value绑定到按钮的isEnabled属性上。

最终我们用Combine实现了MVVM模式的注册业务。


四、性能表现

RxSwift已在开源社区广泛应用,Apple本身推出的Combine的性能表现如何呢?我们使用Will Combine kill RxSwift?的测试代码来比较Combine和RxSwift,代码如下:

class CombineVSRxSwiftTests: XCTestCase {
    private let input = stride(from: 0, to: 1_000_000, by: 1)
    override class var defaultPerformanceMetrics: [XCTPerformanceMetric] {
        return [    XCTPerformanceMetric("com.apple.XCTPerformanceMetric_TransientHeapAllocationsKilobytes"),
            .wallClockTime
        ]
    }


    func testCombine() {
        self.measure {
            _ = Publishers.Sequence(sequence: input)
                .map { $0 * 2 }
                .filter { $0.isMultiple(of: 2) }
                .flatMap { Just($0) }
                .count()
                .sink(receiveValue: {
                    print($0)
                })
        }
    }


    func testRxSwift() {
        self.measure {
            _ = Observable.from(input)
                .map { $0 * 2 }
                .filter { $0.isMultiple(of: 2) }
                .flatMap { Observable.just($0) }
                .toArray()
                .map { $0.count }
                .subscribe(onSuccess: { print($0) })
        }
    }
}

在2019 iMac 16G上测试出Time和Allocation的情况如下:

可以看到Combine的性能惊人,比RxSwift好的不止一个等级。当然Combine本身是闭源的,我们猜测Apple工程师可能使用大量的C/C++代码来优化性能,而RxSwift则是纯Swift实现,性能表现则不是那么特别优异。


五、总结

本文系统的介绍了Combine的Publisher,Subscriber,以及Operator的工作原理,并在了解工作原理的基础上自定义了UIControlPublisher,然后结合实际案例介绍了如何使用Combine实现MVVM模式,最后我们比较了Combine和目前流行的RxSwift,显而易见Combine在性能上有巨大的优势。

Combine只支持iOS13,或许让部分开发者觉得实际离我们还很远,但截止目前,根据Apple在2020WWDC前公布的数据,iOS13设备占有率已达92%以上,相信随着iOS14的到来,iOS13占有率会更高,提前了解和掌握Combine还是很有必要的。

【推荐阅读】

 “携程技术”公众号

  分享,交流,成长

Combine 教程 · 第一章:认识 Combine(SwiftUI 开发者专属视角) 我们将深入讲解 Combine 的三大主角,理解它们的生命周期、如何组合与清理订阅,结合更多小案例。• Combine 是 Apple 原生的响应式框架,SwiftUI 的天然拍档。• SwiftUI 中 @Published、$var 背后都是 Combine。• SwiftUI 的 View 会自动监听 Combine 的更新来重绘界面。• @Published 背后就是 Combine 的 Publisher。• @ObservedObject 是 Combine 的桥梁。 阅读详情

相关推荐

iOS中的依赖注入与Combine框架整合

本文旨在解决iOS开发中依赖管理与响应式编程的整合难题。通过深入剖析依赖注入的设计原则与Combine框架的核心机制,提供一套完整的技术方案,帮助开发者构建松耦合、可测试的响应式应用。内容涵盖基础概念、核心原理、代码实现、实战案例及最佳实践,适用于中高级iOS开发者及架构师。背景介绍:明确技术目标与核心概念核心概念与联系:解析依赖注入与Combine的原理及整合点依赖注入实现模式:基于Swift的三种注入方式详解Combine框架核心机制:Publisher/Subscriber模型与异步数据流处理。

移动开发前沿的博客 963

深入理解bge-small-en的池化策略:mean pooling如何提升嵌入质量

BGE-Small-EN是BAAI(北京智源人工智能研究院)开发的高性能英文文本嵌入模型,专为语义搜索、信息检索和相似度计算等任务优化。这个轻量级模型虽然参数量小,但在MTEB(大规模文本嵌入基准)排行榜上表现出色,这主要得益于其精心设计的池化策略。本文将深入解析bge-small-en的mean pooling池化机制,揭示它如何有效提升文本嵌入质量。 ## 🎯 什么是bge-small-e

gitblog_00076的博客 855

移动开发必备:Combine框架从入门到精通

在移动开发中,异步操作(如网络请求、用户输入、定时器)是绕不开的“麻烦事”。传统的闭包回调、Delegate模式容易导致代码嵌套(“回调地狱”),RxSwift等第三方框架虽强大但学习成本高且依赖外部库。2019年WWDC,Apple推出了Combine——官方原生响应式编程框架,专为Swift设计,完美适配iOS/macOS/watchOS/tvOS,旨在用统一的语法简化异步编程。

移动开发前沿的博客 1072

Combine的介绍与使用

Combine是Apple推出的声明式响应式编程框架,专为Swift设计,适用于iOS 13+和macOS 10.15+。核心概念包括Publisher(数据生产者)、Subscriber(数据消费者)、Operator(数据转换)和Subject(手动发送值)。框架支持链式调用操作符进行数据处理,如map、filter等,并能处理网络请求、错误处理和多个Publisher的组合。在UIKit和SwiftUI中,Combine可实现数据绑定和状态管理,例如文本输入实时搜索和列表更新。其统一API简化了异步事

chenzimin_blog 1545

构建单向数据流的React式系统:使用Apple Combine框架

Apple Combine 是一个由苹果公司为 iOS、macOS、watchOS 和 tvOS 开发者提供的声明式、编译时检查、强类型的响应式编程框架。它允许开发者轻松订阅和处理异步事件序列。Combine 构建了一个统一的响应式编程模型,把事件流中发生的各种事件,如用户交互、系统事件或数据模型的变化,以统一的格式进行处理。在 Combine 框架中,通过定义发布者(Publishers)和订阅者(Subscribers),开发者可以清晰地管理异步数据流和事件。

weixin_29940495的博客 1251

深入解析STM32官方库:.c/.h文件功能与应用场景

本文深入解析了STM32官方库中.c和.h文件的核心功能与应用场景。详细剖析了stm32f10x.h、启动文件、外设驱动文件等关键组件的作用,并通过LED闪烁实战演示了如何构建工程、配置文件和调用库函数。文章旨在帮助开发者理解官方库的架构,掌握高效使用技巧,从而降低STM32开发门槛,提升开发效率与代码质量。

weixin_29189377的博客 346

Combine简介(1)

Combine 是苹果公司在 WWDC 2019 推出的一个函数式响应编程(FRP)框架,主要用于 Swift 开发中处理异步数据流和事件。它简化了数据流管理,将异步操作(例如网络请求、用户交互、通知等)通过声明式编程模型进行组合和处理。

琥珀的博客 642

Windows系统下复现PointNet++算法

本文详细介绍了如何在Windows系统下复现PointNet++算法,内容包括程序下载、环境配置、数据集准备以及三个主要任务(语义分割、分类、部件分割)的实现步骤和常见报错解决方法。通过遵循本文的指导,用户可以顺利完成PointNet++算法的复现。

LingYi_5的博客 4326

Combine 框架,从0到1 —— 1.核心概念

  本文首发于 Ficow Shen’s Blog,原文地址: Combine 框架,从0到1 —— 1.核心概念。     内容概览 前言 核心概念 RxSwift Combine 总结 参考内容   前言   未来已来,只是尚未流行! 响应式编程 这个名词已经久负盛名,但是在实际项目中采用了响应式编程的公司其实不多。如果您有 iOS 开发经历,那么您多半听说过 RxSwift,而 Rx 源自微软。提到Rx,往往也会提到源自微软的 MVVM模式。不过,

Ficow Shen 1226

Minecraft Forge模组开发入门:从环境搭建到事件监听实战

事件驱动编程是一种基于事件和事件监听器的软件架构模式,其核心原理是通过事件总线实现组件间的松耦合通信。在游戏开发领域,这种模式能够有效处理玩家交互、状态变更等异步操作,具有高度的灵活性和可扩展性。Java作为面向对象编程语言,通过注解和反射机制为事件驱动提供了天然支持。Minecraft模组开发正是事件驱动编程的典型应用场景,开发者可以利用Forge框架提供的事件总线监听游戏内各种行为。本文以Minecraft Forge模组开发为例,详细讲解如何通过Gradle构建工具搭建开发环境,并实现自定义方块注册和

culi3182的博客 395

sentaurus学习笔记(一)器件仿真

之前有跟大家说,以后转到sentaurus,因此silvaco会用的比较少,结果发现真的有一点贪心厌旧的感觉,现在基本上不用silvaco(lll¬ω¬)故这篇文章,将为大家带来的是关于sentaurus的结构仿真和器件的特性的提取。我们还是老规矩,先上结构图。 还是一个经典的IGBT结构,这是一个典型的N型IGBT,下面我将把一些相关的结构,和具体的写法用下面一幅图表达出来。 这里因为方便看,我们把器件的比例画的比较抽象。可以看到的是,这里有很多的距离参数是用一些变量名来写的,这也是sentaurus

weixin_43262021的博客 2万+

探索苹果的Combine框架:CombineExamples项目详解

探索苹果的Combine框架:CombineExamples项目详解 项目介绍 CombineExamples 是一个由Pawel Krawiec打造的开源项目,旨在帮助开发者快速上手苹果的最新反应式编程框架——Combine。这个项目提供了一系列简单易懂的例子,涵盖了从用户登录验证到定时器实现,再到GitHub搜索和用户名可用性检查等多种场景,让你在实践中掌握Combine的强大功能。 项目技术...

gitblog_00068的博客 583

UDS诊断服务基础详解之七-31服务

本节内容主要是讲解诊断服务中的31服务,包含31服务的使用场景,请求报文格式,响应报文格式,以及举例对31服务进行相关的说明

车载网络小D的博客 5625

SwiftUI 和 Combine 的学习:一

SwiftUI 和 Combine 的学习:一

xiangxiang07的博客 3117

第1集:面试官视角:AIOps 核心能力模型与面试项目全局搭建【免费试读】

本文介绍了一门面向AIOps工程师的面试实战课程,针对当前运维领域薪资差距明显的痛点,帮助学员系统掌握企业级AIOps平台开发能力。课程承诺提供可直接用于面试和生产环境的代码实现,从零构建模块化AIOps平台。第一集重点讲解了面试官视角下的核心能力模型,并指导学员搭建项目基础环境,包括Python虚拟环境配置、本地大模型部署(Ollama)以及智能巡检Agent的代码实现。课程强调实战导向,通过40集系统讲解,帮助学员实现薪资40-60万的职业跃升。

qq_2937655951的博客 615

勇闯dify v1.0.0之设置模型供应商。解决:Reached maximum retries (3) for URL https://marketplace.dify.ai/

朋友们,大家好,今天带大家来勇闯dify v1.0.0。为什么叫勇闯呢?我就这么说吧,本来我昨天就想带大家勇闯v1.0.0的。但是dify的marketplace访问不了。公司的网和手机热点都试了,就是访问不了。我们连个模型都没有,还勇闯个球啊,对吧,就搁置了。今天,我赶紧看看这个marketplace好了没。一看,可以了。赶紧写下这篇博客,帮助同志们走出困境。

xiezhipu的博客 4616

【IOS】Combine

摘要: Combine 是 Apple 推出的声明式响应式编程框架,用于处理异步事件和数据流,核心包括 Publisher(发布数据)、Operator(转换/过滤数据)、Subscriber(消费数据)。它通过链式操作符(如 map、filter、debounce)简化异步逻辑,支持网络请求(URLSession.dataTaskPublisher)、UI 绑定(@Published 和 assign)、事件合并(merge/zip)等场景。关键优势在于声明式语法和自动管理订阅生命周期(通过 AnyCan

欢迎指错||纠正||建议||水评+点赞&&评论&&关注&&转发 637

第一节:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入门

vben5 快速入门。 Vben Admin 框架新出的版本V5.5.4,而之前的Vben Admin 2.x 目前已存档,仅进行重大问题修复。之前在2.x版本曾经简单完成了一版专栏文章,当时也是收获了一些好评和建议。本次决定在v5 版本基础上再完成一次前后端的搭建。希望大家继续多多支持。项目精简后,再次启动项目,执行 pnpm run dev点击登录,可以看到接口报错,现在前端请求的后端有报错,下一节处理这部分逻辑。

cuiwin的专栏 7059

Swift Combine 学习(一):Combine 初印象

本文是 Swift Combine 七篇学习笔记的开篇,介绍了 Combine 框架的背景、基本概念和核心组件。文章从简述函数响应式编程的角度开始。

tripleEyeAline的博客 1512

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

从第三方到原生:为什么iOS开发者应该拥抱Combine框架

Combine框架是Apple推出的原生响应式编程框架,为iOS开发者提供了一种更高效、更集成的方式来处理异步事件和数据流。对于习惯使用RxSwift的开发者来说,迁移到Combine不仅能获得Apple官方的长期支持,还能更好地与SwiftUI等现代iOS技术栈深度整合,提升应用性能和开发效率。 ## 🌟 Combine vs RxSwift:核心优势对比 Combine作为Apple的原

gitblog_00625的博客 583

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Swift 使用 Combine 进行开发 从入门到精通七

通常从利用现有的发布者、操作符和订阅者来组成管道开始。本书中的许多示例突出了各种模式,其中许多模式旨在对界面内的用户输入提供声明性响应。你可能还希望创建更容易集成到 Combine 的 API。例如,创建一个封装远程 API 的发布者,返回单个结果或一系列结果。或者,你可能正在创建一个订阅者来随着时间的推移去处理和消费数据。

AI架构师易筋 3586

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

RxSwift和Combine的相同点和使用例子

RxSwift 和 Combine 都是响应式编程框架,用于简化异步和基于事件的代码。它们有很多相似之处,主要体现在设计理念和编程模式上。

VictorZhang 1575

Swift中的Combine

Combine 是 Apple 在 iOS 13 中引入的响应式编程框架,它用于处理 Swift 中的异步操作和数据流。通过 Combine,开发者可以将异步操作(例如网络请求、用户输入、通知等)组合成数据流,并对其进行操作和观察。网上搜了下Combine的教程,发现要么是翻译的Apple的文档,要么SwiftUI+Combine直接绑定起来使用,这无疑给没有使用过SwiftUI的同学增加了学习的成本,今天决定写一下自己对Combine的理解希望能帮助到准备入门Combine的同学们。

我叫柱子哥 3669

swift中多线程

首先我们先了解哈希表(hash表)这个概念: 哈希表(hash表):又叫做散列表,是根据关键码值(key value)而直接访问的数据结构。也就是它通过关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射叫做函数,存放记录的数组叫做哈希表。 读到此处我们得到一个关键信息:所谓哈希表就是一个数组,数组中每一个元素称为一个箱子(bin),箱子中存放的是键值对。 hash表存储过程简单介绍: 1.根据key值计算出它的hash值h; 2.假设箱子的个数是n,那么键值对应该放在第(h%n)..

逝水无情的博客 1683

SwiftUI与Combine框架深度解析:heckj/swiftui-notes项目核心解读

Combine是苹果推出的声明式Swift API,用于处理随时间变化的数据流。它代表了苹果对函数式响应式编程(FRP)的实现方案,类似于其他语言中的ReactiveX系列框架。Combine将Swift的静态类型特性与响应式编程范式完美结合,为开发者提供了一套强大的异步事件处理工具。 ### 核心特性解析 1. **声明式编程模型**:通过链式操作描述数据处理流程 2. **强类型安全**:

gitblog_01076的博客 710
上一篇: 干货 | 携程风控数据仓库实践
下一篇: 直播报名 | 携程技术沙龙大数据与AI技术实践
携程技术
博客等级 码龄10年 3715粉丝 324原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值