惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

宝玉的分享
宝玉的分享
酷 壳 – CoolShell
酷 壳 – CoolShell
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Security @ Cisco Blogs
小众软件
小众软件
D
Docker
博客园_首页
A
About on SuperTechFans
P
Privacy International News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
A
Arctic Wolf
Spread Privacy
Spread Privacy
有赞技术团队
有赞技术团队
T
Tailwind CSS Blog
Latest news
Latest news
WordPress大学
WordPress大学
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
The Exploit Database - CXSecurity.com
C
Cybersecurity and Infrastructure Security Agency CISA
大猫的无限游戏
大猫的无限游戏
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
K
Kaspersky official blog
V2EX - 技术
V2EX - 技术
SecWiki News
SecWiki News
U
Unit 42
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LINUX DO - 热门话题
S
Security Affairs
Y
Y Combinator Blog
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
MongoDB | Blog
MongoDB | Blog
博客园 - 【当耐特】
The GitHub Blog
The GitHub Blog
T
Tenable Blog
W
WeLiveSecurity
Cloudbric
Cloudbric
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
Google Developers Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
N
Netflix TechBlog - Medium
F
Full Disclosure
N
News and Events Feed by Topic
D
DataBreaches.Net
P
Proofpoint News Feed
B
Blog RSS Feed
B
Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

美团技术团队

美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团 · 技术团队 美团发布基于 N-gram 全新模型:嵌入扩展新范式,实现轻量化 MoE 高效进化 2025美团技术年货,「马」上到来 多维创新打造强泛化智能体模型,LongCat-Flash-Thinking-2601技术报告发布 美团 EvoCUA 刷新开源 SOTA,会用电脑还会持续进化的智能体! 美团 LongCat-Flash-Thinking-2601 发布,工具调用能力登顶开源 SOTA! KuiTest:基于大模型通识的 UI 交互遍历测试 AAAI 2026 | 美团技术团队学术论文精选 2025 | 美团技术团队热门技术文章汇总 美团 LongCat-Video-Avatar 正式发布,实现开源 SOTA 级拟真表现 大模型剪枝新范式:先浓缩,再剪枝——DenoiseRotator技术解读 LongCat 上线 AI 生图!精准高效,AI 创作不设限 美团发布 LongCat-Image 图像生成模型,编辑能力登顶开源 SOTA AI Coding与单元测试的协同进化:从验证到驱动 R-HORIZON:探索长程推理边界,复旦NLP&美团LongCat联合提出LRMs能力评测新框架 美团 LongCat 发布 AMO-Bench:突破 AIME 评测饱和困境,重新定义 LLM 数学上限 美团 LongCat Interaction 团队发布大模型交互系统技术报告 WOWService 美团 LongCat 团队发布全模态一站式评测基准 UNO-Bench 美团开源LongCat-Audio-Codec,高效语音编解码器助力实时交互落地 NeurIPS 2025 | 美团技术团队论文精选 LongCat-Flash-Omni正式发布并开源:开启全模态实时交互时代 美团 LongCat 团队发布 VitaBench:基于复杂生活场景的交互式 Agent 评测基准 LongCat-Video 视频生成模型正式发布,探索世界模型的第一步 ICCV 2025 | 美团论文精选及多模态推理竞赛冠军方法分享 从0到1建设美团数据库容量评估系统 可验证过程奖励在提升大模型推理效率中的探索与实践 LongCat-Flash-Thinking 正式发布,更强、更专业,保持极速! 开源 | InfiniteTalk:无限长虚拟人视频生成的新范式 美团正式发布并开源 LongCat-Flash-Chat,动态计算开启高效 AI 时代 美团 M17 团队开源 Meeseeks 评测集:揭秘大模型的“听话”能力 可信实验白皮书系列08:开放式分析引擎 | 附PDF合集 美团智能头盔研发实践系列02:软件功能篇 美团智能头盔研发实践系列01:硬件设计篇 ACL 2025 | 美团技术团队论文精选 美团开源OIBench与CoreCodeBench:揭示大模型编程能力的真实水平 可信实验白皮书系列07:高阶实验工具 开源 | MeiGen-MultiTalk:基于单张照片实现多人互动演绎 可信实验白皮书系列06:观察性研究 JDK高版本特性总结与ZGC实践 可信实验白皮书系列05:准实验 可信实验白皮书系列04:随机轮转实验 可信实验白皮书系列03:随机对照实验 可信实验白皮书系列02:AB实验基础 可信实验白皮书系列01:从0到1的方法论与实践指南 MTGR:美团外卖生成式推荐Scaling Law落地实践 OR算法+ML模型混合推理框架架构演进 ICLR&CVPR 2025美团技术团队论文精选 行为正则化与顺序策略优化结合的离线多智能体学习算法 预测技术在美团弹性伸缩场景的探索与应用 美团技术年货 | 600+页电子书,算法、工程、测试、数据、安全系列大合集 鸿蒙应用签名实操及机制探究 2024 | 美团技术团队热门技术文章汇总 AutoConsis:UI内容一致性智能检测 CIKM 2024 | 美团技术团队精选论文解读 大前端:如何突破动态化容器的天花板? KDD 2024 OAG-Challenge Cup赛道三项冠军技术方案解读 新一代实验分析引擎:驱动履约平台的数据决策 大众点评技术部包揽KDD 2024 OAG-Challenge Cup赛道全部3项冠军 ACL 2024 | 美团技术团队精选论文解读 KDD 2024 | 美团技术团队精选论文解读 基本功 | 一文讲清多线程和多线程同步 小程序可测性能力建设与实践 SIGIR 2024 | 美团技术团队精选论文解读 Spark向量化计算在美团生产环境的实践 CVPR 2024 | 美团技术团队精选论文解读 基于多模态信息抽取的菜品知识图谱构建 DDD在大众点评交易系统演进中的应用 美团外卖基于GPU的向量检索系统实践 美团大规模KV存储挑战与架构实践 基于接口数据变异的App健壮性测试实践 美团技术年货 | 600+页电子书,前端、后端、算法、测试、运维系列大合集 美团RASP大规模研发部署实践总结 2023 | 美团技术团队热门技术文章汇总 美团到店终端从标准化到数字化的演进之路 AIOps在美团的探索与实践——事件管理篇 美团技术博客十周年,感谢一路相伴 基于UI交互意图理解的异常检测方法 如何利用「深度上下文兴趣网络」提升点击率? 基于模式挖掘的可靠性治理探索 代码变更风险可视化系统建设与实践 美团多场景建模的探索与实践 MJDK 如何实现压缩速率的 5 倍提升? 如何提供一个可信的AB测试解决方案 KDD 2023 | 美团技术团队精选论文解读 美团前端研发框架Rome实践和演进趋势 斩获CVPR 2023竞赛2项冠军|美团街景理解中视觉分割技术的探索与应用 MySQL自治平台建设的内核原理及实践(下) CVPR 2023 | 美团技术团队精选论文解读 超大规模数据库集群保稳系列之三:美团数据库容灾体系建设实践 超大规模数据库集群保稳系列之二:数据库攻防演练建设实践 Robust 2.0:支持Android R8的升级版热修复框架 超大规模数据库集群保稳系列之一:高可用系统 一次「找回」TraceId的问题分析与过程思考 基于AI+数据驱动的慢查询索引推荐 SOTA!目标检测开源框架YOLOv6 3.0版本来啦
block在美团iOS的实践
xiaoliang · 2014-05-17 · via 美团技术团队

说到block,相信大部分iOS开发者都会想到retain cycle或是__block修饰的变量。

但是本文将忽略这些老生常谈的讨论,而是将重点放在美团iOS在实践中对block的应用,希望能对同行有所助益。

本文假设读者对block有一定的了解。

从闭包说起

在Lisp这样的语言中,有一个概念叫做闭包(closure1),指的是一个函数以及它所处的词法作用域(lexical scope2)构成的整体。为了理解闭包,我们首先来看看什么是词法作用域。

所谓词法作用域,顾名思义,是指一个符号引用的是其词法环境中的变量,而无关程序在运行时的状态。这么说可能有点抽象,让我来看一段Common Lisp3代码:

(defvar printer (let ((x 42))
		  (lambda () (format t "~a" x))))

这里我们定义了一个变量printer,它的值是一个函数,这个函数会打印词法作用域中的变量x(其值为42)。

现在我们来调用这个函数:

CL-USER> (funcall printer)
42

可以看到,我们调用了printer中存放的函数之后,打印出来的数字是42,跟我们的预期相符。

接下来再让我们看一个可能会出乎意料的结果:

CL-USER> (let ((x 1))
	   (funcall printer))
42

我们在调用之前把x设置为了1,但是打印的结果仍然是42。

为什么?因为printer中存放的函数在被调用时所引用的变量位于其词法作用域中, 即该函数被定义时所处的词法环境中,所以程序在运行时设置的变量x对函数不起作用。

前面我们讲过,所谓闭包,就是函数及其词法作用域的合称,具体到上例,那么匿名函数和x就构成了一个闭包,它会为函数保存一种状态,有点类似于全局变量,不过除了那个匿名函数,其他函数无法访问到x。

说了这么多,似乎跟block毫无关系?事实上,block为C带来了闭包。

Block

Apple从OS X 10.6和iOS 4以后开始支持block,让我们用C把上面的例子重写一下:

#include <stdio.h>

int main ()
{
    int x = 42;
    void (^block)() = ^() {
        printf("%d\n", x);
    };
    block();
    x = 1;
    block();

    return 0;
}

编译运行后得到的输出同样是两个42。

到了这里,相信读者对闭包已经有一个直观的认识了,但是它有什么用?有什么好处?

设想如下场景,我们要请求一个URL,并以block的形式传入回调函数,并在回调函数中用到刚才这个URL:

NSURL *someURL = …;
[SomeClass getURL:someURL finished:^(id responseObject) {
	// process responseObject with someURL
}];

这里网络请求是异步的,所以当block中代码执行时,getURL:finished:方法调用所在的栈很可能已经不存在了,但是因为回调block和someURL构成了closure,所以即使栈不存在,block仍然可以引用到someURL。

可能你会说,“我在block中增加一个NSURL类型的参数,把someURL传回来不也可以实现同样的目的吗?”不妨设想如果我们在block中要引用的对象有10个之多,用参数列表传递明显不再现实,用容器类或者专门定义一个类来传递虽然可以,但是前者没有编译器为我们检查错误,后者则相当繁琐。而利用闭包,可以轻易达到灵活性和简洁性的平衡。事实上,美团客户端就大量利用了闭包,在UI层发出请求,在回调中更新某些UI组件。

函数式编程4

在Lisp中,函数是一等公民,可以随时创建、作为参数传递、作为返回值返回,Objective C在没有block之前,没有类似的机制,有了block,Objective C也就具备了函数式编程的能力,block是对象,有自己的ISA指针,可以随时创建,作为参数传递,作为返回值返回。

先来看看block的经典用法:

[UIView animateWithDuration:0.25 animations:^{
            self.view.alpha = 1.0f;
        }];

UIView的animateWithDuration:animations:方法的第二个参数是一个block,它把跟动画相关的操作封装起来传递进去,以实现动画效果。

现在让我们发掘一下类似的用法:

[SAKBaseModel comboRequest:^() {
 [dealModel fetchDealByID:123456
               withFields:nil
               completion:^(MTDeal *deal, NSError *error) {
                   ...
               }];
 [orderModel fetchOrderByID:654321
             withDealFields:nil
                 completion:^(MTOrder *order, NSError *error) {
                ...
             }];
}];

这里我们为SAKBaseModel设计了一个类似于UIView的接口叫comboRequest,它会接受一个block作为参数,在这个block中发出的请求都会作为combo请求的一部分。如果dealModel或者orderModel的任何一个请求不是出现在block中,那么它就是一个普通的请求。这样做的好处是dealModel和orderModel的接口不需要关心自己是不是属于一个combo请求,调用者则可以灵活地调整代码。

那么怎么实现这样的接口呢?还是从UIView上获取灵感。我们知道UIView有个方法setAnimationsEnabled:,实际上SAKBaseModel也可以有这么一个方法:setComboRequestEnabled:,而在comboRequest方法的实现中,在调用传进来的block之前先setComboRequestEnabled:YES,调用完后再恢复为原状态。相应的,在实际的model接口中,检查comboRequest是否为YES,如果是,则把自己作为一个combo请求的一部分,否则正常发出请求即可。

Think Big

Lisp最强大的特性之一是condition系统,它可以分离异常的检测、异常的解决和异常解决方式的决策,看一段示例代码:

(define-condition network-timeout-error (error)
	((url :initarg :url :accessor url)))

(defun try-again (condition)
	(let ((restart (find-restart ‘try-again)))
	  (when restart (invoke-restart restart))))

(defun deal-requester (deal-id)
	(handler-bind ((network-timeout-error #’try-again))
	  (request-from-url (format nil “http://api.mobile.meituan.com/deal/~a” deal-id)
	    (lambda (deal error)
		(if error
		    (format t “error: ~a”, error)
		    (process-deal))))))
(defun request-from-url (url finished)
	(let ((callback (lambda (response error)
			  (if (network-timeout-error-p error)
				(error ‘network-timeout-error :url url)
				(funcall finished (parse-deal response) error)))))
	  (restart-bind
	    ((try-again (lambda () (http-request url callback))))
	    (http-request url callback))))

可以看到,condition系统对于代码的分层提供了良好的支持,请求超时的错误在底层代码被检测到,在发出请求前注册一个restart,而在业务层去决定要不要调用restart。

一直以来,C语言要实现优雅的异常处理就是一件不简单的事情,而Objective-C虽然加入了try-catch支持,但是苹果并不鼓励使用,那么能否实现类似于condition系统这样的异常处理机制呢?

答案是能。让我们来看看接口设计:

typedef void (^RESTART)(id userInfo);
typedef void (^HANDLER)(id condition);

void restart_bind(void (^body)(), NSString *restartName, RESTART restart, ...) NS_REQUIRES_NIL_TERMINATION;

void handler_bind(void (^body)(), Class class, HANDLER handler, ...) NS_REQUIRES_NIL_TERMINATION;

void notify(id condition);

RESTART find_restart(NSString *restartName);

如下图所示,handler_bind首先在栈中注册好handler,而restart_bind则在handler有效的环境中注册restart,当有异常发生时,notify函数会在当前环境中寻找handler,找到后,控制会转移到上层的handler代码中,这时handler可以用find_restart在栈中搜索restart,找到之后可以调用,从而实现异常的恢复,做完这一切,控制回到notify发生的点继续向下执行。

完整的代码敬请期待美团iOS的开源项目。

有了SAKCondition,我们可以实现任意底层代码的逻辑穿透到上层代码,比如网络层和UI层,使得上层代码可以在不了解下层代码实现细节的情况下调用恢复机制。事实上,美团的iPhone客户端就是利用SAKCondition实现了美团账户的安全解锁功能。

总结

block给Objective C带来了无穷的可能性。本文只讨论了美团iOS在实践中的一些用法,更多想法还在等待挖掘。