
字节笔记本
2026年10月7日 · 约 2 分钟读完
结束通知发出时条目已空
状态对象里有是否正在拖、拖的是哪条字符串、是否已经离开窗口、起点和计时器。开始拖动时把标记设为真,记下字符串和起点,并启动计时器。计时器间隔 0.1 秒,闭包用弱引用。
清空发生在发送之前
停止函数先把正在拖设为假,离开标记设为假,字符串设为 nil,起点设为 nil,计时器作废。然后打印 Sending dragEnded notification。原来的发送只有名字和空的 object,注释却写着会带上被拖条目。更新后的发送加了 userInfo,键是 item,值却是刚刚被设成 nil 的那个属性。收到通知时,条目已经是空的。要带上原来的字符串,得在清空之前先存一份。
放下的 performDrop 会调用停止函数并返回真。结束通知依赖这次放下。没有发生放下时,停止函数不会从这里被调用,结束通知也不会从这里发出。用户说没有触发,要先确认放下确实走到了这个方法。
计时器发的是另一个名字
检查函数取第一个窗口和起点。用 mouseLocationOutsideOfEventStream 看当前点,再用内容视图的 bounds 判断是否在里面。内容视图用了强制解包,视图不在时会直接崩溃。内外状态和上次不同,才把 isLeavingWindow 改掉,并发送 dragStateChanged,userInfo 里同样有 item。这个名字不是 dragEnded。计时器不会发结束通知。

两个名字注册成 dragStateChanged 和 dragEnded。片段里没有订阅它们的代码。发送成功和有人收到是两件事。没有订阅者时,打印那句仍然会出现,界面却像没收到。
坐标来自窗口,包含判断用的是内容视图的 bounds。两套坐标系不一致时,人还在窗口里也会被算成已经离开,或相反。对话没有做坐标转换。

开始拖动不会发结束通知。结束只在停止函数里。停止函数又把计时器废掉,所以离开状态不会在结束之后继续刷。
弱引用在对象释放后是空的。计时器若在对象之后还响,检查不会执行。这和条目被提前清空是两个空。



