I'm running into an error trying use Xcode Live Previews in my project.
Our main project is really large and previews have never worked there, so I've been creating smaller targets with fewer dependencies and have had some luck getting previews to work there.
So now I'm starting to move a feature over into a Feature Module (an isolated target with tests and an example iOS host app to demo it).
The demo app runs fine, but the previews never work for me.
I filed a FB on this with some detail: FB9162267
Things I have tried:
Changing my preview provider to just render Color.blue - same result
Looked in ~/Library/Logs/DiagnosticReports for a crash related to the preview agent - nothing
Read through the generated report, mentions a Library not loaded @rpath/SomeDependency, but I can see this dependency successfully built in the Derived data build artifacts for the preview build
Project setup is like this:
Example - iOS app
Pods - Some internal pods + a few external ones
The internal pods are all path based references, so I can edit them directly in this workspace.
Example app depends on FeatureModuleA which is a framework built by the Pods project.
My preview lives in FeatureModuleA.
Any ideas on what I can do next?
Post
Replies
Boosts
Views
Activity
We tried to adopt OSLog in past years, but it was really cumbersome to retrieve the logs from customers.
Doing a sysdiagnose is a really cumbersome task for most non-technical users to perform. Additionally they contain WAY more information than we need and are generally very large.
This is true for macOS and iOS apps.
Are there any new facilities for retrieving just the logs for a given subsystem that we could trigger with code, for instance in a help menu?
I'm exploring a sine wave rendering, and have built my view to have 3 controllable parameters:
phase (to control the offset and allow animating "horizontally")
amplitude (to control how high each peak is)
frequency (how many complete waves there are)
I'd show you a screenshot but these forums not only don't allow embedded images, but you can't even link to one. (grrr)
My SineWave is implemented as a Shape, so it is already Animatable. I made amplitude and frequency an AnimatablePair and expose it as my shape's animatable data like this:
var animatableData: AnimatablePair<CGFloat, CGFloat> {
get { .init(frequency, amplitude) }
set {
frequency = newValue.first
amplitude = newValue.second
}
}
This works, and I get a nice animation if I do this in my containing view:
SineWaveShape(phase: phase, amplitude: amplitude, frequency: frequency)
.stroke(style: StrokeStyle(lineWidth: 3, lineCap: .round, lineJoin: .round))
.foregroundColor(.red)
.onAppear {
withAnimation(Animation.spring(response: 0.5, dampingFraction: 0.4, blendDuration: 0.1).repeatForever()) {
amplitude = 0.1
frequency = 4
}
}
Now I want to animate the phase as well. But I don't want this one to autoreverse, and I want it to be much faster. Unfortunately adding another withAnimation block next to this one has no effect, even if I have it as part of my animatable data. The last animation block always wins.
How should I approach this problem of wanting to animate two properties with two different Animation instances?
Following the SwiftUI tutorials, I have a PageViewController like this:
struct PageViewController: UIViewControllerRepresentable {
var controllers: [UIViewController]
@Binding var currentPage: Int
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
pageViewController.dataSource = context.coordinator
pageViewController.delegate = context.coordinator
return pageViewController
}
func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) { 	
				pageViewController.setViewControllers(
						[controllers[currentPage.wrappedValue]],
						direction: .forward,
						animated: true,
						completion: nil)
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var parent: PageViewController
init(_ pageViewController: PageViewController) {
parent = pageViewController
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let index = parent.controllers.firstIndex(of: viewController) else {
return nil
}
if index == 0 {
return nil
}
return parent.controllers[index - 1]
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let index = parent.controllers.firstIndex(of: viewController) else {
return nil
}
if index == parent.controllers.endIndex - 1 {
return nil
}
return parent.controllers[index + 1]
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed,
let visibleViewController = pageViewController.viewControllers?.first,
let index = parent.controllers.firstIndex(of: visibleViewController) {
parent.currentPage.wrappedValue = index
}
}
}
}
This works just like in the tutorial. You use it by providing a binding for the page:
struct PageView<Page: View>: View {
var viewControllers: [UIHostingController<Page>]
@State var currentPage = 0
init(_ views: [Page]) {
self.viewControllers = views.map { UIHostingController(rootView: $0) }
}
var body: some View {
VStack {
ZStack(alignment: .bottomTrailing) {
PageViewController(controllers: viewControllers, currentPage: $currentPage)
}
HStack {
Button(action: self.navigatePrevious) {
Image(systemName: "arrow.left")
}.disabled(currentPage == 0)
Text("Current page: \(currentPage)")
Button(action: self.navigateNext) {
Image(systemName: "arrow.right")
}.disabled(currentPage == self.viewControllers.count - 1)
}
}
}
		// ...
}
So here's my problem. I want to move the navigation controls up in the view tree. So I first change the @State var to a @Binding so that the parent can mutate it (as well as the coordinator)
When the parent changes the currentPage, this causes the PageView and PageViewController to be re-rendered.
This ends up breaking the UIPageViewController. It will no longer scroll.
On Stack Overflow there was a suggestion to give the PageViewController a unique identifier like this:
PageViewController(controllers: viewControllers, currentPage: $currentPage)
.id(UUID())
This gets around the above issue by forcing it to consider it a new view and re-creating the UIViewController. But it also breaks animations when you set currentPage programmatically.
What can I do to to fix this?