Skip to main content

Aguarde as expectativas com o tempo limite para sempre


Waitforexpectationswithtimeout forever
Estou escrevendo testes de integração no Xcode 6 para acompanhar meus testes funcionais e de unidade. O XCTest tem um método setUp () que é chamado antes de cada teste. Ótimo!
Ele também tem o XCTestException, que me permite escrever testes assíncronos. Também ótimo!
No entanto, gostaria de preencher meu banco de dados de teste com dados de teste antes de cada teste e o setUp apenas começar a executar testes antes que a chamada do banco de dados assíncrono seja feita.
Existe uma maneira de ter setUp esperar até que meu banco de dados esteja pronto antes de executar testes?
Aqui está um exemplo do que tenho feito agora. Como o setUp retorna antes que o banco de dados seja preenchido, eu tenho que duplicar muitos códigos de teste em todos os testes:

Waitforexpectationswithtimeout forever
Tentando usar um dispatch_sempahore. Deve ser algo como isto:
Isso deve se comportar corretamente, mesmo se runSomeLongOperationAndDo: decide que a operação não é realmente longa o suficiente para merecer threading e é executada de forma síncrona.
Recentemente, cheguei a esse problema novamente e escrevi a seguinte categoria no NSObject:
Dessa forma, posso facilmente transformar uma chamada assíncrona com um retorno de chamada em um síncrono em testes:
Além da técnica de semáforo coberta exaustivamente em outras respostas, agora podemos usar o XCTest no Xcode 6 para realizar testes assíncronos via XCTestExpectation. Isso elimina a necessidade de semáforos ao testar o código assíncrono. Por exemplo:
Para o bem dos leitores futuros, embora a técnica de semáforo de envio seja uma técnica maravilhosa quando absolutamente necessária, devo confessar que vejo muitos desenvolvedores novos, não familiarizados com bons padrões de programação assíncrona, gravitando muito rapidamente para semáforos como um mecanismo geral para fazer assíncronas. rotinas se comportam de forma síncrona. Pior que eu tenha visto muitos deles usam essa técnica de semáforo da fila principal (e nunca devemos bloquear a fila principal em aplicativos de produção).
Eu sei que este não é o caso aqui (quando esta questão foi postada, não havia uma boa ferramenta como o XCTestExpectation; também, nestes conjuntos de testes, nós devemos garantir que o teste não termine até que a chamada assíncrona seja feita). Essa é uma daquelas raras situações em que a técnica de semáforo para bloquear o thread principal pode ser necessária.
Então, com minhas desculpas ao autor desta pergunta original, para quem a técnica do semáforo é boa, eu escrevo este aviso para todos aqueles novos desenvolvedores que vêem essa técnica de semáforo e considerem aplicá-la em seu código como uma abordagem geral para lidar com assíncrono. métodos: Esteja avisado que nove vezes em dez, a técnica de semáforo não é a melhor abordagem ao se montar operações assíncronas. Em vez disso, familiarize-se com os padrões de bloqueio / fechamento de conclusão, bem como padrões e notificações de protocolo delegado. Geralmente, essas são maneiras muito melhores de lidar com tarefas assíncronas, em vez de usar semáforos para fazê-las se comportarem de maneira síncrona. Geralmente, há boas razões para as tarefas assíncronas terem sido projetadas para se comportarem de maneira assíncrona, portanto, use o padrão assíncrono correto em vez de tentar fazê-las se comportar de maneira síncrona.

在 Swift 应用 应用 Grand Central Dispatch (下)
以及 第一 部分 中 , , , , , 以及 以及 以及 以及 以及 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让使用 用户 , , 了 用户 体验。 , , 使用 使用 使用 CPU 密集型 任务 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用
A Internet é uma das seguintes: Le Internet 通过 添加 照片 时 , 会有 提示 框 框 在 图片 下载 完成 之前 就 弹出 , 如下 图 :
在于 在于 PhotoManager download 的 downloadPhotosComCompletar :
打开 PhotoManager. swift , 替换 downloadPhotosComComplicação :
dispatch_group_wait disp 所有 任务 都 完成 直到 超时。 如果 在 任务 完成 前 就 超时 了 , , 会 会 一个 非零 非零 值 值。 可以 通过 值 来 判断 是否 等待 超时 ; 不过 , 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用, 它 会 永远 等待! 没关系 , 因为 图片 总是 会 下载 完 的。
Nota: Developer 网速 太快 以至于 分辨 不出 何时 执行 执行 的 包 包 , , , 修改 修改 设备 设备 的 的 的 在 在 Configuração 中 的 Seção de Desenvolvimento。 打开 Condicionador de Conexão de Rede , 选择 & rdquo; Rede Muito Ruim & rdquo;
用 的 用 , , 用 用 用 调度 到 队列 然后 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用
在 PhotoManager. swift 找到 找到 downloadPhotosComCompletion : 替换 之 :
注意 循环 的 的 的 次数 次数 , , , 太多 循环 循环 循环 每个 每个 循环 循环 只有 只有 很小 很小 很小 的 的 的 的 工作量 , 的 的 的 的 的 掉 掉 并发 并发 带来 带来 的 的。 str str str str str str str str str str str str str str str str str你 在 每次 循环 中 做 多 件 工作。
调用 你 的 的 的 并发 执行 执行 ; ; 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用
运行 aplicativo , 用 Le Internet 添加 一些 图片 , 发现 不同 了 吗?
在 真 机 上 运行 运行 新 的 的 的 会 发现 发现 的 的 的 的 的 的 提升 提升。。 但是 但是 吗 吗 吗?
比 很 可能 因为 并行 而 花费 了 比 para 循环 更多 的 的。。 应该 结合 结合 合适 合适 的 的 的 长 长 非常 非常 大 大 的 的 的 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用
iOS 8 和 OS X Yosemite (了 调度 对象 块 (objeto de bloco de despacho)。 它们 实现 起来 对 对 闭 再 再 再。。。 调度 块 块 可以 做到 很多 很多 , , , , 队列 队列 中 中 的 的 的 的 设置 QoS 等级 来 决定级 , , 最 显 显 著 的 的 是 是 是 可以 取消 块 的 的 的 开始。。 明白 对象 对象 只有 在 在 它 它 执行 才 才 才 可以 可以 取消 ((一旦 开始 执行 执行 就 不能取消 了)。
Internet 说明 这个 问题 , , 用 用 用 Le Internet 下载 一些 图片 , 替换 替换 替换 替换 替换 替换 替换 替换 PhotoManager.
Internet , 从 Le Internet 添加 图片。 你 会 看到 app 下载 张 图片 图片 , , , , 随机 数量 数量 的 的 刻意 图片 设计 的 那些 没 下载 下载 的 的 的 是 因为 在 在 加入 队列 后 后 后 被 取消 取消 了 了 这 这 是 一个 刻意 设计 的 的 的 的 例子 , 但是 很好的 演示 了 怎样 使用 调度 调度 对象 块 以及 如何 取消 它。
Tem certeza que você pode encontrar informações sobre o Edsger W. Dijkstra no: a 7.7 / 5/2016 Página Anterior Próxima Página Índice
打开 GooglyPuffTests. swift 掉 替换 掉 downloadImageURLWithString :
1. 创建 信号 量。。 参数 表明 信号 量 起始值。 这个 值 代表 了 起始 阶段 阶段 获取 信号 量 量 的 的 的 的 的 用 用 用 , , , , , 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用。 2. 在 完成 闭 包 中 , 你 告诉 信号 量 不再 需要 需要 资源。 这 信号 信号 量 增加 , , , , 等待 等待 等待 资源 的 的 的 , , , , , , , , 信号 量 量 可用。
Esta página foi útil para você: Clique para ampliar 0 , 线程 可以 获取 获取 它 , 注释 3 中 对 信号 量 量 的 的 的 的 的 的 会 阻塞 阻塞 阻塞。 只有 只有 在 图片 下载 好 了 以后 了 以后 以后 了 了 了 了 了 了 了 了 了 了 了 了 了 了 了注释 发送 发送 一个 信号 量 , 那么 注释 3 对 信号 量 的 的 的 就 就 成功 了 , , , 的 的 等待。。 但 如果 图片 图片 失败 呢 呢? 就 不会 调用 注释 2 这句 触发 信号 的 语句 , 那么 注释 3 就会 等待超时 , 测试 失 败。)
Produto / Teste 或 cmd + U 运行 测试。 测试 应该 成功。
XCTest X 提供 了 另 一种 一种 一种 使用 期望 来 测试 异步 代码 代码 的 的 的 的 的 这种 特性 特性 让 你 首先 设置 你 的 的 的 的 的 m & & & 的 的 的 的 的 的 的 的 的 的 的 & & & & & 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的等待 , 异步 任务 将 期望 期望 标记 为 已 完成。

Teste da interface do usuário: falha ao obter instantâneo atualizado.
Depois de pressionar um botão que carrega uma nova página, recebo um erro dizendo "Falha no teste da interface do usuário - Falha ao obter instantâneo atualizado"
A página anterior onde eu pressiono o botão funciona bem. Todos os objetos podem ser tocados e modificados.
Quando eu passar para a próxima página, nada poderá ser pressionado. Lembro-me de que durante o vídeo da WWDC no teste da interface do usuário, o cara disse que, quando os monitores mudam, os elementos são reavaliados para obter os dados mais atuais. Isso não está funcionando agora? Alguém mais teve esse problema / sabe de uma correção?
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Estou tendo o mesmo problema.
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Por favor, preencha os relatórios de bugs (usando o link Report Bugs na parte inferior desta página) para que possamos analisar seus problemas. Obrigado!
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Acredito que estou vendo isso no Xcode 7.3 também. Bug # é 25427379.
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Joar, você sabe de alguma atualização sobre esse bug? obrigado.
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Tem um relatório de bug arquivado para isso?
Eu estou recebendo os mesmos problemas.
Atividade de teste da interface do usuário:
Falha de Asserção: Falha no Teste da UI - Falha ao obter o instantâneo de atualização Erro Domain = XCTestManagerErrorDomain Code = 13 "Erro ao copiar os atributos -25202" UserInfo =
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Por favor arquive um relatório de bug do seu próprio! Obrigado.
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Eu também tenho o mesmo problema.
Falha de Asserção: Falha no Teste da UI - Falha ao obter o instantâneo de atualização Erro Domain = XCTestManagerErrorDomain Code = 13 "Erro ao copiar os atributos -25202" UserInfo =
& lt; unknown & gt;: 0: erro: - [ShutterstockAcceptanceTests. ShutterstockAcceptanceTests testCreateAndDeleteLightbox]: Falha no teste de interface do usuário - Falha ao obter o instantâneo de atualização Erro Domain = XCTestManagerErrorDomain Code = 13 "Erro ao copiar atributos -25202" UserInfo =
Existe alguma atualização sobre esse bug?
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Eu estou recebendo o mesmo problema.
Isso me ajudou Mostrar 0 Likes (0)
Re: teste da interface do usuário: falha ao obter o instantâneo atualizado.
Ei - para qualquer um que tenha esse problema (eu também estou) você pode indicar quais controles estão na tela que está sendo exibida quando você vê esse erro? Para mim, estou vendo isso com controladores de exibição que contêm um WKWebView. Se eu nunca exibir um controlador de visualização que contenha um WKWebView, não vejo o erro. Eu estaria interessado em ouvir se outros tiverem descobertas semelhantes (talvez com outros controles). A boa notícia é que consegui enviar um relatório de bug com código de trabalho e um teste de interface do usuário que falha quase 100% do tempo.
Além disso, desligando animações durante o teste.

Pense diferente.
我们 可以 一次 一次 去撞 南墙 , 但 不能 一个 一个 失去 理想.
在 Swift 应用 应用 Grand Central Dispatch (下)
以及 第一 部分 中 , , , , , 以及 以及 以及 以及 以及 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让 让使用 用户 , , 了 用户 体验。 , , 使用 使用 使用 CPU 密集型 任务 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用
A Internet é uma das seguintes: Le Internet 通过 添加 照片 时 , 会有 提示 框 框 在 图片 下载 完成 之前 就 弹出 , 如下 图 :
在于 在于 PhotoManager download 的 downloadPhotosComCompletar :
调用 在 方法 方法 的 最后 调用 conclusão 闭 包 —— 你 会 想当然 的 的 的 的 的 图片 图片 都 下载 完了 完了。 但 但 不幸 的 的 是 , 在 此时 无法 保证。
DownloadPhoto Faça o download da URL 下载 图片 并且 不等 下载 完成 就 立即 退出。 换言之 , Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用一个。
Download, DownloadPhoto (url :) 是 异步 并且 立即 返回 的 —— 所以 目前 的 方式 不能 正常 工作。
DownloadPhotosComCompletion completion 在 所有 图片 下载 任务 任务 都 完成 调用 自己 自己 自己 自己 的 conclusão 闭 包。 问题 是 : 你 怎么 监视 并发 并发 的 的 的 的 事件 事件 呢 呢? 你 不 不 知道 它们 何时 完成 , , 以 何种 顺序。
多个 你 可以 用 多个 Bool 多个 来 追踪 下载 下载 情况 , , , 容易 容易 扩展 扩展。 而且 坦白 讲 , , , 是 很 丑陋 丑陋 的 代码。
(组 (Grupos de expedição)
组 在 一 组 组 任务 都 都 完成 后 会 发出 通知。。 任务 任务 可以 是 异步 或 或 同步 的 的 的 的 的 的 的 的 的 的 的 的 来 通知 分布 在 在 不同 不同 的 的 的 调度 调度 还 可以 可以 可以 同步 或 或 或 的 的 的 的 的 的 的 的 的 来 来 来 来。。。 任务 在 不同 不同 的 队列 中, Disptch_group_t 实例 用来 追踪 队列 中 的 不同 任务。
是 一种 是 dispatch_group_wait , 它 会 阻塞 当前 进程 , 直到 所有 任务 都 完成 或是 或是 或是 等待 超时 超时。 这 正是 正是 我们 的 的 的 中 需要 需要 的 的 的 的 的 的 的
打开 PhotoManager. swift , 替换 downloadPhotosComComplicação :
使用 使用 dispatch_group_wait 使用 了 当前 进程 , 要用 要用 要用 要用 要用 要用 要用 要用 要用 后台 后台 后台 后台。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。保证 保证 dispatch_group_enter 和 dispatch_group_leave 是 成对 ​​调用 的 的 , 程序 程序。。。 通知 已经 已经 已经。。 再 一次 , , 保持 进 和 出 相 匹配 匹配。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 , ,用 会 返回 一个 非零 值。 可以 通过 返回 值 来 判断 是否 等待 超时 不过 , , 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 的 的 的 的 的 的 的 的时 , 可以 保证 所有 所有 图片 任务 都 完成 完成 晚些时候 超时 了 主 线程 接下来 在 执行 队列 中 完成 完成 闭。。 闭 包 晚些时候 晚些时候 会 会 在 主 主 线程 中 执行 执行。 执行 闭 包。
Nota: Developer 网速 太快 以至于 分辨 不出 何时 执行 执行 执行 的 包 包 , , , , 修改 设备 设备 的 的 在 在 在 Developer Developer Developer Developer Developer Developer Developer Developer Developer Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Very Rede Muito Ruim。
好 定义 串行 队列 : 好 选择。。 是 是 不错 不错 的 完成。。 但 你 要 要 谨慎 地 在 在 主 队列 中 使用 , 因为 同步 等待更新 任务 会 阻塞 主 线程。。 , , , , 需要 较长 较长 较长 的 的 的 (((网络 网络) 完成 , , , 更新 更新 更新 更新 更新 更新 : : : : :: 好 选择。 用于 调度 组 和 通知。
用 的 用 , , 用 用 用 调度 到 队列 然后 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用 用
在 PhotoManager. swift 找到 找到 downloadPhotosComCompletion : 替换 之 :
放进 的 不需要 不需要 不需要 方法 方法 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进 放进。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 。 当下 , 你 需要 在 主 队列 中 执行 闭 包。
看看 PhotoManager 中 的 downloadPhotosComCompletion 通过 你 会 发现 通过 para 循环 下载 了 三张 图片 图片。 现在 来 看看 看看 能否 通过 并发 执行 para 循环 来 提速。
出 时候 请 出 dispatch_apply 了。
disp disp disp disp disp 会 并发 执行 执行 循环 循环 过程。。 这个 是 是 同步 的 的 , 所以 像 普通 ​​的 for 循环 一样 , disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp
注意 循环 的 的 的 次数 次数 , , , 太多 循环 循环 循环 每个 每个 循环 循环 只有 只有 很小 很小 很小 的 的 的 的 工作量 , 的 的 的 的 的 掉 掉 并发 并发 带来 带来 的 的。 str str str str str str str str str str str str str str str str str str你 在 每次 循环 中 做 多 件 工作。
用 时候 用 dispatch_apply 合适?
替换 baixarPhotosComCompletion 如下 :
调用 你 的 的 的 并发 执行 执行 ; ; 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用 调用
运行 aplicativo , 用 Le Internet 添加 一些 图片 , 发现 不同 了 吗?
在 真 机 上 运行 运行 新 的 的 的 会 发现 发现 的 的 的 的 的 的 提升 提升。。 但是 但是 吗 吗 吗?
使用 很 可能 因为 并行 而 花费 了 比 for 循环 更多 的。。。 应该 结合 结合 结合 合适 的 的 的 的 长 长 非常 非常 大 大 的 的 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 — — — — — — — — — — — — — — — — — — — — — — — 用 就 优化 那些 值得 优化 的 的 用 用 用 用 用 Instrumentos 测试 以 找到 最 耗时间 耗时间 的 的 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 使用 的 的增加 复杂 性。
iOS 8 和 OS X Yosemite (了 调度 对象 块 (objeto de bloco de despacho)。 它们 实现 起来 对 对 闭 再 再 再。。。 调度 块 块 可以 做到 很多 很多 , , , , 队列 队列 中 中 的 的 的 的 设置 QoS 等级 来 决定级 , , 最 显 显 著 的 的 是 是 是 可以 取消 块 的 的 的 开始。。 明白 对象 对象 只有 在 在 它 它 执行 才 才 才 可以 可以 取消 ((一旦 开始 执行 执行 就 不能取消 了)。
Internet 说明 这个 问题 , , 用 用 用 Le Internet 下载 一些 图片 , 替换 替换 替换 替换 替换 替换 替换 替换 PhotoManager.
扩展 endereços 数组 , 每个 地址 地址 3 份。 这个 数组 用来 保存 保存 接下来 创建 创建 的 的。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。继承 进入 的 的 那里 那里 那里 继承 继承 继承 继承 o 第二 第二 个 参数 是 闭 包 包 形式 的 的 的 的 定义 定义 定义。 块 被 被 异步 的 的 到 到 到 队列 队列 队列 队列 用 用 用 主 队列 队列 队列 队列 因为 因为 它 它 是 一个 一个 串行 队列 , 可以 方便 我们 取消 对象Photos。 当前 代码 已经 已经 在 主 线程 中 中 执行 着 , Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos Photos 的 的 的 的 的 的 的 的 的 的 的 的 的 的 的4 随机 返回 一个 arc arc arc arc arc arc arc arc arc arc arc arc arc arc arc arc arc 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 1 , 则 取消 块。 前提 是 , 块队列 中 并且 没 开始。 块 块 在 执行 的 的 的 中 中 不可以 不可以 不可以 取消 的 的。 因为 所有 块 都 加入 调度了, 不要 忘记 移除 被 取消 的 那些 块.
Internet , 从 Le Internet 添加 图片。 你 会 看到 app 下载 张 图片 图片 , , , , 随机 数量 数量 的 的 刻意 图片 设计 的 那些 没 下载 下载 的 的 的 是 因为 在 在 加入 队列 后 后 后 被 取消 取消 了 了 这 这 是 一个 刻意 设计 的 的 的 的 例子 , 但是 很好的 演示 了 怎样 使用 调度 调度 对象 块 以及 如何 取消 它。
G 的 GCD 趣 用.
Xcode 中 的 在 运行 在 XCTestCase 的 类 类 , , , , 会 运行 所有 以 teste 开头 的 以。 测试 跑 跑 跑 主 主 线程 下 , , , , , , 认为 认为 认为 认为 测试 是 顺序 执行 的。
Tem certeza que você pode encontrar informações sobre o Edsger W. Dijkstra no: a 7.7 / 5/2016 Página Anterior Próxima Página Índice
打开 GooglyPuffTests. swift 掉 替换 掉 downloadImageURLWithString :
1. 代码 中 信号 量 的 的 的 : : 创建 信号 量。。 参数 表明 信号 量 起始值。。。 这个 值 代表 了 起始 阶段 阶段 可以 信号 信号 信号 量 的 的 的 的 数目 数目 增加 信号 信号 量 就是 信号 , , , 用 用 用 用 用 用 用 用 用。 当前 没有 线程 可以 获取 信号 量)。 2. 在 完成 闭 包 中 , , 告诉 告诉 信号 信号 量 不再 需要 资源。 这 这 信号 信号 量 量 , , , , 等待 等待 等待 等待 资源 的 的 的 , , , , , , , , , , 信号 量 可用 可用。 3. 等待 信号 量 并 设置 超时 时间。 这个 调用 调用 会 当前 进程 直到 收到 信号。。 非 10 秒 — — — — 这种 情况 , , , , , , 超过 请求 不 应该 超过的 此时! (译者 注 :: 说 下 我 的 的 : : : : 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是 是注释 了 以后 , 才会 发送 一个 信号 量 , 那么 注释 3 对 信号 量 的 的 的 就 成功 成功 , , , , , 等待 等待。。 但 但 图片 下载 下载 失败? 就 不会 调用 注释 2 这句 触发 信号 的 语句, 那么 注释 3 就会 等待 超时, 从而 测试 失败.)
((Expectativas)
XCTest X 提供 了 另 另 使用 期望 来 测试 异步 代码 代码 的 的 的 的。 这种 这种 特性 让 你 你 设置 你 的 的 的 期望 — — — 的 的 的 — — — — — — — — — — 开始 异步 异步 异步 异步。。 接下来 接下来 会 一直 等待 , 直到 异步任务 将 期望 标记 为 已 完成。
替换 GooglyPuffTests. swift download 的 downloadImageURLWithString :
: 原理 : 1. 用 expectationWithDescription 生成 期望。 测试 会 在 日志 上 上 显示 其中 其中 其中 的 的 的 参数 , , , 调用 你 期望 发生 发生 的 的。。。。。。 调用 调用 调用 调用 调用 调用 调用. 用 线程 用 waitForExpectationsWithTimeout 调用 期望 达成。 如果 等待 超时 会 视为 出错。
使用 测试。 结果 和 使用 信号 量 没什么 , , 使用 使用 使用 XCTest 框架 是 更 清晰 易读 的 的 方案。
(源 (Fontes de despacho)
GCD 中 存在 一个 特别 有趣 有趣 的 的 的 , , , , , 包含 底层 功能 功能 功能 的 的 的 , 监控 监控 监控 监控 监控 des des descritores de arquivo 监控 , 端口 端口 , 端口 , , 端口 , Mach Mach Mach Mach 。 所有 这些 都 超出 了 本 本 教程 的 范围 , 但是 你 可以 尝试 着 使用 一下 调度 源 对象。
理解 一次 使用 调度 源 的 的 的 的 可能 可能 会 迷失 其中 , , 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解 理解
参数 一个 参数 tipo: dispatch_source_type_t 是 最 重要 的 参数 , 因为 它 描述 了 句柄 (identificador (和 掩码 (máscara) 参数。 你 需要 查看 Xcode 弄清楚 来 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚 弄清楚
监视 你 会 监视 DISPATCH_SOURCE_TYPE_SIGNAL。 如 文档 所述 :
Unix 从 列表 可以 从 signal. h 一串。 在 顶部 有 一串 #define。 在 这些 信号 列表 中 , 你 将 要 监控 SIGSTOP 监控。 这个 信号 会 在 进程 进程 接收 到 到 不可抗拒 不可抗拒 的 的 的 的 的 的 指令 指令 指令 指令 被 被 发送 发送 这个 这个 与 与 与Deb Depurador LLDB 调试 程序 时 发送 的 信号 相同。
进入 C 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 进入 和 和 和 和 和 和 和 和 和 和 和 和 和 和 ALAssetLibrary : :
在 代码 有点 难懂 , , 注释 来 来 : : 最好 只 在 DEBUG 在 下 编译 这段 代码 , , ,。。 很多 信息 信息]:] 在 Configurações do Projeto & ndash;> Configurações de Compilação & ndash ;> Swift Compiler - Custom Flags & ndash;> Outros Swift Flags & ndash;> Debug 下 添加 - D DEBUG。 2. 用 dispatch_once 一次性 初始化 调度 源。 3. 初始化 signalSource 变量。 你 指明 对 信号 感兴趣 并且 并且 SIGSTOP 做 第。 参数。 除此之外 , , 主 主 队列 接收 接收 到 的 的 事件 — 你 你 会 发现 为什么。 4. 如果 参数 错误 , , , 对象 不会 不会 不会 创建 创建。 因此 , , , , , 在 使用 它 它 之前 确保Disp 源 是 有效 的 的 disp disp disp disp 5. disp 情况 调度 闭 闭 disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp disp。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 ,想 监视 事件 时 , 必须 让 源 对象 继续 执行。
在 viewDidLoad 中 的 NSLog 语句 处 设置 断点。 暂停 暂停 调试 , , , ; ; ; 会 ; ; 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 到 使用 使用 使用 使用 使用 使用 使用 使用 使用便捷!

Atualização do iOS 9: Por que meus testes de unidade ficaram paralisados?
Uma investigação sobre por que a atualização do iOS 8 para 9 SDK levou a testes lentos.
Ao atualizar o Square Register do iOS 8 para o iOS 9, descobrimos que o comportamento do nosso teste de unidade foi alterado de maneira difícil de diagnosticar. Investigamos a questão e refizemos nossos passos para chegar à causa raiz. Por fim, descobrimos que o problema subjacente não era apenas específico do Square, mas um problema que poderia afetar qualquer desenvolvedor do iOS.
Testes agora são lentos, não confiáveis.
Com quase 7 anos, o Square Register for iOS é um aplicativo pesado que contém mais de um milhão de linhas de código. Embora a transferência do SDK de base do iOS 8 ou do iOS 9 pareça direta, a grande escala dessa mudança apresentou muitos desafios.
O principal desses desafios envolveu a suíte de testes do aplicativo. Logo após a implementação da alteração, percebemos que nosso pacote de testes de unidade - com seus milhares de testes executados para cada construção - havia diminuído significativamente e acabaria por falhar. Essas falhas de teste nunca ocorreram quando executadas individualmente, mas muitas vezes falharam como parte de um conjunto maior de testes e nem sempre da mesma maneira. Como nenhum teste foi defeituoso, uma explicação plausível indicou a poluição do ambiente de teste compartilhado.
É a fila principal!
O próximo passo foi reduzir o tamanho do nosso palheiro. Começamos comentando os testes para restringir o escopo. Comentários de arquivos após arquivos tornaram-se tediosos - incluímos um truque de categoria que facilita a vida (abaixo). Infelizmente, a melhor maneira de executar apenas um subconjunto de testes que correspondam a um padrão de nomenclatura no iOS não existe:
Acima: uma categoria útil para executar somente um conjunto específico de testes que correspondam a algum padrão de sequência.
Usando esse filtro, reduzimos a um punhado de classes de teste para reproduzir consistentemente uma falha. Então percebemos uma coisa curiosa: não importava exatamente quais testes estavam sendo executados em si; foi a quantidade de testes que determinaram o resultado.
Vimos que o conjunto de testes precisava ser executado por cerca de três minutos; menos e todos eles passam. Um teste em particular falharia antes de todos os outros, e se tornou o foco do resto da investigação:
Acima: a falha do teste principal que tentamos rastrear. Observe o uso de girar o runloop (aguardando a expectativa) e travar.
A falha ocorreu depois de girar a ranhura, ou seja, a expectativa nunca foi satisfeita. Estávamos esperando que o trabalho fosse realizado em uma fila, mas o teste expiraria. Então, decidimos olhar para todas as filas ...
Ah ha! A fila principal já estava entupida com um número excessivo de operações no momento em que chegamos ao teste do problema em nosso teste maior:
Nós encontramos o culpado: os testes foram lentos porque o mainQueue estava sobrecarregado, e nossa primeira falha no teste foi devido à espera de uma operação de desbloqueio que estava presa nessa fila.
Para demonstrar que a fila era a fonte de problemas, adicionamos uma chamada a [[NSOpertaionQueue mainQueue] cancelAllOperations] no método tearDown do teste; os testes passaram agora!
Percorrendo linha por linha e observando as alterações em [[NSOpertaionQueue mainQueue] operationCount], rastreamos isso em um módulo específico que foi chamado ao configurar os equipamentos de teste. Ele adicionaria 4 operações de agendamento ao mainQueue para cada equipamento de teste que foi criado (um para cada setUp). Essas operações se acumulariam porque não lhes foi dada a oportunidade de drenar a principal parte. Isso explica por que um grande conjunto de testes exibiu o problema, mas um conjunto menor não o fez.
Parecia que o caso estava fechado. Estávamos prontos para fazer alguns ajustes no módulo em questão e “encerrar o dia”, mas esse “dia” em particular não seria “chamado” tão prontamente e o caso permanece aberto!
Na verdade não é isso!
Corrigimos o problema de agendamento com o dispositivo de teste, mas descobrimos que ainda havia um problema.
Primeiro, tentamos verificar a correção corrigindo NSOperationQueue de forma que ela recusasse todos os outros trabalhos adicionados na fila principal de operação, exceto pelo trabalho realizado pelo teste com falha.
Má notícia: o fracasso ainda aconteceu, mas agora, foi preciso uma suíte de testes muito maior para reproduzir! A falha ocorreria mesmo quando o mainQueue tivesse apenas uma operação para executar, e era intrigante porque essa fila - com apenas uma única operação - não seria drenada. Claramente não foi um caso de a fila ser meramente “batida” como se pensava anteriormente.
Em outras palavras, o mesmo teste ainda aguardava para sempre uma operação no mainQueue, mesmo quando o mainQueue se parecia com isso:
A operação de desbloqueio ainda estava presa na fila, mesmo quando nada mais estava na fila!
Recuando.
Como a falha do nosso teste se manifestou como um deadlock (bloqueio que nunca é liberado), nós cavamos o código de sincronização (trecho abaixo) e procuramos as condições da corrida em seguida. Como os testes corriam em paralelo, parecia plausível, mas isso era coisa de palha. Embora freqüentemente pensássemos que estávamos em algo, chegávamos de mãos vazias quando procurávamos encontrar uma condição de corrida.
Mesmo que a fila principal e os bloqueios estejam envolvidos, e não importa o quanto desejássemos encontrar uma condição de corrida, esse não era o problema.
Fora das ideias, começamos a dividir o teste do problema para ver o que veio à tona. Nós comentamos ou substituímos o máximo que pudemos para reduzir seu escopo, e até mesmo substituímos o XCTestExpectation por fiação laminada a mão.
Um acidente feliz.
Eu cometi um erro com a conversão da unidade de tempo enquanto estava substituindo waitForExpectationsWithTimeout, e agora o teste giraria para 1000x a duração pretendida. Parei o depurador quando ele girou e notei algo curioso. Mais frequentemente do que não, pausar o depurador iria pousar em processPendingChanges, um método que NSManagedObjectContext usa para salvar as atualizações CoreData.
Embora pausar o depurador enquanto o teste do problema girou foi uma das primeiras coisas que eu tentei (e desisti), eu não consegui nada interessante até este momento (os Instrumentos também poderiam ter fornecido uma pista se eu tivesse pensado em usar o depurador). Time Profiler). Um par de chances perdidas, mas agora estávamos em algo.
A recorrência de processPendingChanges durante a espera parecia interessante, mas precisávamos de mais informações para determinar o que significava.
Para ver quantos NSManagedObjectContext s estavam chamando processPendingChanges, incluímos o registro de instâncias em nossa classe NSManagedObjectContext usando um NSHashTable estático (semelhante ao exemplo abaixo):
Subclassificamos o NSManagedObjectContext e adicionamos o acompanhamento de instâncias semelhante ao exemplo acima.
Usando esse rastreamento de instâncias, descobrimos que centenas e potencialmente milhares desses contextos estavam persistindo entre execuções de teste. Pior ainda, eles realizariam trabalhos no runloop principal, e parecia plausível que esses contextos vazados estivessem privando os NSOperationQueues do runloop.
Em outras palavras, houve um (aviso de metáfora mista) stampeding rebanho de NSManagedObjectContext processPendingChanges chamadas durante o runloop que privou nosso NSOperationQueue. Nossa mainQueue não conseguiu drenar porque essa avalanche de chamadas programadas consumiu toda a largura de banda disponível do runloop em cada ciclo.
É um vazamento de memória!
Ok, então NSManagedObjectContext estava sendo retido (vazou) entre execuções de teste. Isso reduziu-se a descobrir onde a contagem de retenções do objeto foi aumentada, onde foi diminuída e por que a primeira era maior que a segunda.
Felizmente, o Xcode vem com uma ferramenta chamada Instruments, que possui uma ferramenta Leaks Diagnostic. Então, clicamos com o botão direito no nome do teste e selecionamos o Perfil SQOTAdditionsTest e voila. Os instrumentos deixaram tudo claro. ERRADO! Infelizmente, nada disso aconteceu, começando com os instrumentos se anexando através deste menu:
Frustrantemente, esse recurso Xcode simplesmente inicia uma instância inerte de Instrumentos em vez de anexar a um processo.
Em vez disso, para criar um perfil de uma execução de teste, tivemos que:
definir um ponto de interrupção no código, executar o teste, lançar instrumentos, anexar cuidadosamente ao processo correto por identificação de processo (pode haver duplicatas na lista suspensa) e clique em Gravar.
A ferramenta Leaks não considerou o NSManagedObjectContext (um SDManagedObjectContext nas capturas de tela abaixo) como um vazamento, porque acabou sendo demolido. Mas ele relatou uma lista de pares de retenção / liberação. Então, nós olhamos para uma lista de mais de 6000 retenções / liberações para um único objeto. Na época, não vimos o culpado, então voltamos para a depuração via lldb.
Depois de muita depuração e imprimindo a [context retentionCount], descobrimos que o método save: do contexto adiciona uma retenção e, se comentamos essa linha, o contexto foi limpo como esperado (!), E o vazamento foi plugado.
Voltei para a Instruments para conferir seu relatório com essa nova informação e, com certeza, lá estava:
Lo, uma retenção não pareada.
Uma visão detalhada da retenção que leva ao vazamento:
Visualização detalhada de Instrumentos: o rastreamento de pilha inclui salvar :, CFRetain e _registerAyncReferenceCallback (sic)
Para depurar, sobrescrevi e também configurei um ponto de interrupção simbólico para [NSManagedObjectContext (_NSCoreDataSPI) performWithOptions: andBlock] (com base na saída de instrumentos acima). Não sou fluente em montagem, mas consegui acompanhar lendo os comentários:
Na linha 91, aumentamos nossa contagem de retenções. Na linha 132, adicionamos trabalho assíncrono a uma fila.
Deduzimos que quando save: é chamado, o contexto está enfileirando algum trabalho e mantendo-se nesse meio tempo (percorrendo e chamando p (int) [$ esi retainCount] confirmou isso). Esse trabalho também diminui a contagem de retenções, mas, como permanece na fila, o contexto de auto-retenção permanece para sempre. Também percorremos o uso do sqlite3 e do. dump para verificar se nenhum dado foi perdido se o trabalho enfileirado nunca fosse executado.
Pensando que finalmente entendemos o que está acontecendo, nos afastamos para criar um pequeno projeto de teste para isolar nossas suspeitas e confirmar que o problema está presente em um exemplo mais simples. Está confirmada! O projeto de amostra exibiu o mesmo problema (experimente!).
Usando pontos de interrupção simbólicos para determinar as diferenças de comportamento no Xcode 6 v. 7.
Comparamos o iOS 8 vs o iOS 9 usando este projeto de teste. Ficou claro: salvar: não é assíncrono no iOS8! **
** Deixe-me qualificar isto: (tanto quanto eu posso dizer a partir da montagem) iOS 8 save: foi síncrono em seu “caminho de código padrão” e não enfileirou o trabalho com dispatch_async. A partir do iOS 9, ele agora é assíncrono e invoca imediatamente o dispatch_async como parte de seu “caminho de código padrão”. Incentivo a verificar o projeto de amostra e compará-lo no Xcode 6 vs. Xcode 7 (compare o masterbranch com xcode-6).
Infelizmente, a única maneira de obter o trabalho assíncrono do contexto do mainQueue é girar o runloop. If left alone, operations will build up in the background, and when the runloop finally does run, the contexts will starve the operation queues.
So, our fix is to add code that looks like this to tearDown:
Some contexts were still leaked after this, but these were legitimate memory leaks from services that weren’t fully torn down.
Ensuring all of our t’s are dotted, I add conditional breakpointing to the context’s dealloc breakpoint, and have it play a sound and halt when there are more than 2 dozen instances hanging around:
Playing a sound and using a condition means we can let the tests run and get alerted when too many instances piled up.
Although it takes a while to work through the entire test suite, thanks to our instance tracking, it’s a mechanical process to track down the remaining leaks and verify that none remain.
After tracking down the remaining leaks and adding some runloop spinning at tearDown, the runloop is clear and the tests are 28% faster. Although it took a considerable amount of time to debug, hopefully this time lost is repaid in the future via shorter, stabler test runs–not to mention we got a blog post out of it.

Comments