Originalmente, pensei que o primeiro era apenas uma reexportação do último, mas parece que não é o caso. Qual é a diferença entre as duas pin!
macros e como decidir qual usar?
bli00's questions
Estou usando esta biblioteca de câmeras na qual o autor envolve um AVCaptureVideoPreviewLayer
dentro de um UIViewControllerRepresentable
( link ) para usá-lo como uma visualização da câmera. Dentro updateUIViewController
, o autor enfileira a frame
atualização com DispatchQueue.main.async
:
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
previewLayer.videoGravity = gravity
if previewLayer.superlayer == nil {
uiViewController.view.layer.addSublayer(previewLayer)
}
// print(uiViewController.view.bounds) -- point A
DispatchQueue.main.async {
// print(uiViewController.view.bounds) -- point B
self.previewLayer.frame = uiViewController.view.bounds
}
}
Pode haver discrepâncias entre point A
e point B
, o que faz sentido, pois o uso DispatchQueue.main.async
não garante o pedido, mas não estou totalmente convencido de que essa abordagem esteja correta. Quero poder definir frame
essa visualização usando algo como Preview().frame(width: 350, height: 500)
. No entanto, a falta de ordem aqui significa que dependendo de outras partes do aplicativo/visualizações, a view.frame
atualização acontece em um cronograma desconhecido . Por exemplo, o seguinte:
import SwiftUI
import Aespa
@Observable
class ViewModel {
@ObservationIgnored var aespaSession = Aespa.session(with: AespaOption(albumName: nil))
@ObservationIgnored var preview: InteractivePreview {
aespaSession.interactivePreview(
gravity: .resizeAspectFill,
option: InteractivePreviewOption()
)
}
var show = false
}
struct ContentView: View {
@State var viewModel = ViewModel()
var body: some View {
ZStack {
VStack {
Spacer()
Button("Show Camera Preview") {
viewModel.show.toggle()
}
}
.ignoresSafeArea()
.zIndex(0)
if viewModel.show {
VStack {
viewModel.preview
.frame(width: 350, height: 500)
Spacer()
}
.zIndex(1)
}
}
}
}
Impressões:
Point A: (0.0, 0.0, 393.0, 852.0)
Point B: (0.0, 0.0, 350.0, 500.0)
Mas se você alterar o código para outra coisa, talvez um plano de fundo diferente em .zIndex(0)
(não mostrarei o código exato aqui, pois meu aplicativo não é trivial), ele poderá imprimir:
Point A: (0.0, 0.0, 393.0, 852.0)
Point B: (0.0, 0.0, 393.0, 852.0)
Então minha pergunta é. Qual é a maneira correta de definir view.frame
? updateUIViewController
obviamente está sendo chamado em alguma ordem determinística, mas não antes de bound
"estabelecer". Não vejo um método mágico "updateViewOneLastTime"?
Preciso animar manualmente algo quadro a quadro no SwiftUI usando CADisplayLink
, o que me fornece atualizações quadro a quadro. Para animar um valor de a
to b
de forma linear, a implementação é trivial, basta calcular uma taxa de mudança (b-a) / duration
e aplicar esse delta ao valor em cada quadro.
No entanto, não estou encontrando nenhuma informação sobre como fazer atualizações quadro a quadro quando a animação não é linear . Posso, é claro, criar as funções de atenuação sozinho usando, por exemplo, o pacote numérico , mas parece um caso de uso muito comum para precisar de tanta implementação manual.
Onde estão as funções de flexibilização prontas para uso da Apple? Deveria haver um pacote de funções de easing que me permita recuperar y
usando x
, mas este post sugere que não há nenhum?
CLLocationManager
fornece uma maneira de reagir às alterações de autorização por meio do método do delegado locationManagerDidChangeAuthorization
, mas não consegui encontrar o equivalente para outros tipos de permissão. Ou seja, o acesso à câmera ou à biblioteca de fotos parece não fornecer nenhuma maneira de reagir ao usuário ao configurar e alterar a autorização.
Acho que poderia me aprofundar em cada método que chamo e detectar qualquer erro relacionado à negação da permissão do recurso, mas essa é uma abordagem realmente inferior. Existe uma maneira de reagir de forma determinística às alterações de autorização em geral para o desenvolvimento do iOS?
Eu tenho um método chamado render
que é chamado em cada quadro para desenhar algo na tela usando Metal. Ele está renderizando uma série de pontos armazenados dentro da classe. No entanto, ocasionalmente preciso atualizar esse conjunto de pontos. Estou lutando para encontrar uma solução que possa atualizar esses pontos de maneira segura para a simultaneidade.
Ou seja, ao render
tentar acessar esse array, outro thread pode estar atualizando-o, causando uma falha. Além disso, render
é síncrono e não pode bloquear ou aguardar a atualização. Este parece ser um problema de simultaneidade comum, por isso estou procurando ajuda aqui para ver quais soluções existem.
Para generalizar o problema - há alguma função síncrona que é chamada com muita frequência, ela precisa de acesso a um dado que pode ser atualizado por outro thread. Eu tenho controle sobre o render
método e o "outro" thread que faz a atualização. Como posso evitar que uma condição de corrida trave o aplicativo? (só não precisa travar, não há considerações de "correção" dos dados)
Uma possível solução que eu hipotetizei é usar atômicos. Não tenho certeza de como isso poderia ser feito, especialmente em Swift (não acha que Swift tem atômicos?)
EDITAR:
Tentarei adicionar mais contexto aqui, mas pode ser difícil adicionar um MRE, considerando que parte do que estou implementando está guardado em um repositório privado ao qual não tenho acesso.
Resumindo, estou tentando implementar uma camada personalizada do MapBox seguindo este exemplo . Os detalhes desta render
função específica no exemplo são irrelevantes, pois meu método de renderização precisa fazer algo completamente diferente, mas seria algo assim em pseudocódigo:
class MyCustomLayer: NSObject, CustomLayerHost {
var locationData: [CLLocation] = []
func render(...) {
// calculate the viewport from the parameters
let viewport = ...
if viewport.fitSomeCondition {
// fetch new location data. This can't block and needs to happen async
fetchLocationDataFromServer(viewport: viewport)
// need to somehow update the locationData
}
// render locationData
}
}
Aqui locationData
está uma matriz de longitudes e latitudes e render
está separada do CustomLayerHost
protocolo do MapBox iOS SDK . O código-fonte de como CustomLayerHost
é tratado não está disponível ao público, mas aqui está a declaração do cabeçalho:
/**
* Render the layer. This method is called once per frame.
*
* This method is called if underlying map rendering backend uses Metal graphic API.
*
* @param The `parameters` that define the current camera position.
* @param The MTLCommandBuffer used to render all map layers.
* Use to create new command encoders. Do not submit as there could be map
* layers following this custom layer in style's layer list and those won't get
* to be encoded.
* @param The MTLRenderPassDescriptor that defines rendering map to view drawable.
*
*/
- (void)render:(nonnull MBMCustomLayerRenderParameters *)parameters
mtlCommandBuffer:(nonnull id<MTLCommandBuffer>)mtlCommandBuffer
mtlRenderPassDescriptor:(nonnull MTLRenderPassDescriptor *)mtlRenderPassDescriptor;
Entendo que este não é um MRE, mas espero que ajude a tornar a questão mais clara.
Eu tenho uma visualização onde a parte superior é a Map
e a parte inferior é arredondada View
, atualmente, quando esta tela é exibida, a Map
visualização para onde as duas visualizações se encontram com uma lacuna muito óbvia. Existe uma maneira de mesclar as duas perfeitamente para que o mapa aparece como se estivesse em segundo plano?
VStack {
Map(position: $position) {
UserAnnotation()
}
.mapStyle(.standard(elevation: .realistic))
.ignoresSafeArea()
List {
ForEach(locationManager.debugMessages, id: \.self) { msg in
Text(msg)
}
}
.cornerRadius(30)
}