iOS键盘扩展documentContextBeforeInput仅重启后生效问题求助
iOS键盘扩展(KeyboardKit)中documentContextBeforeInput首次读取无响应问题
问题现象
使用KeyboardKit开发iOS键盘扩展时,replaceDocumentText函数存在异常:首次点击读取按钮时,读取光标前上下文的循环while let previousContext = textProxy.documentContextBeforeInput, !previousContext.isEmpty完全不执行,但宿主文本框内确实有内容;关闭并重新打开键盘后,该循环恢复正常工作。
可能原因分析
- UITextDocumentProxy初始化绑定延迟:首次加载键盘时,
textProxy可能尚未与宿主文本框完成完整绑定,导致documentContextBeforeInput返回空值或异常状态。 - 异步时序问题:代码中依赖
Task.sleep等待状态,但首次执行时的等待时长不足以让textProxy完成上下文同步。 - 空白字符误判:
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
相关产品推荐
相关产品推荐

