You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS键盘扩展documentContextBeforeInput仅重启后生效问题求助

iOS键盘扩展(KeyboardKit)中documentContextBeforeInput首次读取无响应问题

问题现象

使用KeyboardKit开发iOS键盘扩展时,replaceDocumentText函数存在异常:首次点击读取按钮时,读取光标前上下文的循环while let previousContext = textProxy.documentContextBeforeInput, !previousContext.isEmpty完全不执行,但宿主文本框内确实有内容;关闭并重新打开键盘后,该循环恢复正常工作。

可能原因分析

  1. UITextDocumentProxy初始化绑定延迟:首次加载键盘时,textProxy可能尚未与宿主文本框完成完整绑定,导致documentContextBeforeInput返回空值或异常状态。
  2. 异步时序问题:代码中依赖Task.sleep等待状态,但首次执行时的等待时长不足以让textProxy完成上下文同步。
  3. 空白字符误判:documentContextBeforeInput可能返回包含空白字符的字符串,直接用isEmpty判断会误判为无内容。

解决方案

方案1:添加重试机制,应对首次同步延迟

修改读取前上下文的循环逻辑,增加重试次数,避免首次读取失败直接退出:

var retryCount = 0
let maxRetries = 3
while retryCount < maxRetries {
    if let previousContext = textProxy.documentContextBeforeInput, !previousContext.isEmpty {
        context = previousContext + context
        startingOffset += previousContext.count
        textProxy.adjustTextPosition(byCharacterOffset: -previousContext.count)
        try? await Task.sleep(nanoseconds: 50_000_000)
        retryCount = 0 // 成功读取后重置重试计数
    } else {
        retryCount += 1
        try? await Task.sleep(nanoseconds: 100_000_000) // 等待后重试
    }
}

方案2:优化空值判断逻辑,排除空白字符干扰

将isEmpty判断改为剔除空白字符后检查长度,避免因空白字符导致的误判:

while let previousContext = textProxy.documentContextBeforeInput, 
      previousContext.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 {
    context = previousContext + context
    startingOffset += previousContext.count
    textProxy.adjustTextPosition(byCharacterOffset: -previousContext.count)
    try? await Task.sleep(nanoseconds: 50_000_000)
}

方案3:利用KeyboardKit上下文同步事件触发读取

监听KeyboardContext的textContextDidChange事件,确保在上下文稳定后再执行读取操作:

// 在键盘ViewModel中添加监听(需导入Combine)
private var cancellables = Set<AnyCancellable>()

func setupContextListener() {
    keyboardContext.$textContextDidChange.sink { [weak self] _ in
        guard let self = self else { return }
        // 在此触发replaceDocumentText逻辑,确保上下文已同步
    }.store(in: &cancellables)
}

代码优化建议

  • 移除withCheckedContinuation的冗余包装,直接异步返回结果即可:
    if suggestionsRequired {
        await self.getSuggestions()
    }
    return (self.promptText, self.promptCount)
    
  • 避免使用try?隐式忽略Task.sleep的错误,建议明确处理或使用try await(若允许抛出异常)。

内容的提问来源于stack exchange,提问作者Umair Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 07:52:18