I'm currently writing a macro which outputs Swift Testing code:
// Macro code ...
@MainActor
@SnapshotSuite
struct MySuite {
func makeView() -> some View {
Text("a view")
}
}
which expands to...
// Expanded macro code ...
@MainActor
@Suite
struct _GeneratedSnapshotSuite {
@MainActor
@Test(.tags(.snapshots))
func assertSnapshotMakeView() async throws {
let generator = SnapshotGenerator(
testName: "makeView",
traits: [
.theme(.all),
.sizes(devices: .iPhoneX, fitting: .widthAndHeight),
.record(false),
],
configuration: .none,
makeValue: {
MySuite().makeView()
},
fileID: #fileID,
filePath: #filePath,
line: 108,
column: 5
)
await __assertSnapshot(generator: generator)
}
}
In short, this macro creates snapshot tests from a function.
This all works but I'm finding a couple of limitations, potentially with how Macros are expanded in Swift.
Xcode diamonds are not visible
The snapshots tag isn't discovered
There are a couple of things worth noting though:
The suites and tests are discovered in Xcode's Test Navigator each time Xcode runs tests (cmd + u) - although they need to rerun to be updated.
I manually add a @Suite in my code as well as my @SnapshotSuite to all of the suites.
(The tags never seem to be available though)
Couple of questions on this:
Is this a known issue?
Are there any workarounds?
I do wonder if there's a workaround for showing the diamonds with XCTest APIs such as:
https://github.com/swiftlang/swift-corelibs-xctest/tree/main
https://developer.apple.com/documentation/xctest
Post
Replies
Boosts
Views
Activity
Instead of implementing a textview from scratch (UITextInput it a lot of work/boilerplate)
It makes sense for me to subclass UITextView.
However, when subclassing it seems this is limited to TextKit 1 only, I get an assertion failure:
*** Assertion failure in -[_UITextKit1LayoutController initWithTextView:textContainer:], _UITextKit1LayoutController.m:72
I thought I would just need to call the super init:
super.init(usingTextLayoutManager: true)
But this isn't a designated initialiser:
Must call a designated initializer of the superclass 'UITextView'
Is there a way to do this and override the layout manager so that it uses TextKit 2 in the subclass?
(My aim is to then draw the fragments manually using TextKit2 to get a custom layout while ultimately using all of the UITextView implementation as 99% of it is what I want - other than custom drawing of text fragments).
My code is below:
class DocumentTextView: UITextView {
private let _textLayoutManager = NSTextLayoutManager()
private var textContentStorage: NSTextContentStorage {
textLayoutManager!.textContentManager as! NSTextContentStorage
}
override var textLayoutManager: NSTextLayoutManager? {
_textLayoutManager
}
init() {
let textContainer = NSTextContainer(size: .zero)
super.init(frame: .zero, textContainer: textContainer)
_textLayoutManager.textContainer = textContainer
textContentStorage.attributedString = NSAttributedString(string: text, attributes: [
.foregroundColor: UIColor.label,
])
textContentStorage.addTextLayoutManager(_textLayoutManager)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I'm trying to unpack this sentence
Note that after adding a second text container to the layout manager, the text views become uneditable and unselectable.
Found on this example code:
https://developer.apple.com/documentation/uikit/textkit/display_text_with_a_custom_layout
I'm implementing my own UITextInput which makes use of the example code setup to replicate a multi-page text editor (kind of like a basic version of Pages/Word)
Each page has its own NSTextContainer which gets added to one NSLayoutManager.
The code works and my views are rendering text across each page, however, only the first text view is editable.
It appears this is "by design" (?)
How do we get around this? Is there another level we have to drop down to enable multiple editing containers?
The sample code is wayback in iOS 13, so it would seem very odd if the capability of multiple editable text fields/containers was impossible to achieve.
Hellooo,
I’m looking to implement an OpenAI assistant using APIs but I want to do this locally on a group of files.
I want to be able to train a GPT on the contents of a folder for example.
Does anyone have any experience in this?
It seems OpenAI needs a lot of uploading on each request if I were to do this with their API after playing around (but this feels like I’m missing something). It’s also quite costly to use.
I was hoping to use local machine learning and models but this is quite limited in what it can do (eg Lumachain)
Originally asked on Swift Forums: https://forums.swift.org/t/using-bindable-with-a-observable-type/70993
I'm using SwiftUI environments in my app to hold a preferences object which is an @Observable object
But I want to be able to inject different instances of the preferences object for previews vs the production code so I've abstracted my production object in to a Preferences protocol and updated my Environment key's type to:
protocol Preferences { }
@Observable
final class MyPreferencesObject: Preferences { }
@Observable
final class MyPreviewsObject: Preferences { }
// Environment key
private struct PreferencesKey: EnvironmentKey {
static let defaultValue : Preferences & Observable = MyPreferencesObject()
}
extension EnvironmentValues {
var preferences: Preferences & Observable {
get { self[PreferencesKey.self] }
set { self[PreferencesKey.self] = newValue }
}
}
The compiler is happy with this until I go to use @Bindable in my code where the compiler explodes with a generic error,
eg:
@Environment(\.preferences) private var preferences
// ... code
@Bindable var preferences = preferences
If I change the environment object back to a conforming type eg:
@Observable
final class MyPreferencesObject() { }
private struct PreferencesKey: EnvironmentKey {
static let defaultValue : MyPreferencesObject = MyPreferencesObject()
}
extension EnvironmentValues {
var preferences: MyPreferencesObject {
get { self[PreferencesKey.self] }
set { self[PreferencesKey.self] = newValue }
}
}
Then @Bindable is happy again and things compile.
Is this a known issue/limitation? Or am I missing something here?
When running a SwiftUI Multiplatform app in Xcode Cloud I'm getting the following error:
CIWatcher encountered an error in CIWatcherTests failed with:
Failed to install or launch the test runner. (Underlying Error: Could not launch “CIWatcherTests”. Runningboard has returned error 5. Please check the system logs for the underlying cause of the error. (Underlying Error: The operation couldn’t be completed. Launch failed. (Underlying Error: Launchd job spawn failed)))
This runs fine on iOS and all those tests pass.
The SwiftUI app on Mac is a menu bar app so I'm not sure if this could be the issue as it's not launching for some reason on the Xcode Cloud system? Maybe I need to add some run option to make this work?
When run locally both iOS and macOS pass all the tests successfully
Sometimes we just want to use modifiers but don't have a view to draw to the screen, for example an .overlay {} modifier on a view needs a view inside it before you can add modifiers on to that overlay view.
The current approach for this type of thing seems to be Color.clear and while I've seen this almost everywhere I'm not sure if this is
a) the officially recommended way to do this in SwiftUI and
b) the only way to do this in SwiftUI?
I have the following custom view in my project just to avoid the explicit use of Color.clear
import SwiftUI
struct ClearView: View {
var body: some View {
Color.clear
}
}
Are there any other ways to do this?
Note - this is of course not the same as EmptyView() - where Color.clear renders a view with a transparent colour and EmptyView which doesn't render anything at all.
When: Embedding a Image with a symbol effect in a stack view in SwiftUI, and putting this in a List
Actual: The symbols animate when scrolling that item in and out of the view
Expected: The symbol doesn't animate until the value changes.
I have the following code which is boiled down from my actual code where the animating value is a @Model object property (other animations work fine when their animation's value is watching the same property.)
I've boiled it down to the below examples:
The top example works as expected (no symbol animations on scroll)
The bottom example animates the symbols every time they scroll in to view
#Preview {
VStack {
List {
ForEach(1...100, id: \.self) { index in
Image(systemName: "square.3.layers.3d")
.symbolEffect(.bounce, value: index)
}
}
List {
ForEach(1...100, id: \.self) { index in
HStack {
Image(systemName: "square.3.layers.3d")
.symbolEffect(.bounce, value: index)
}
}
}
}
}
This happens on Mac and iOS.
I'm running Xcode 15.3 RC2 but it also happens in Xcode 15.2
I've found this will happen whether embedding in a HStack, VStack or ZStack but seems fine in a Group.
I've tried adding a id() modifier to the HStack to give it an explicit identifier but this doesn't seem to work.
Is there something I'm missing here?
Throughout the various way across the internet of capturing a screenshot of the entirety of a UIScrollView's contents (not just the clipped viewport), all pieces of code seem to fail and draw the correct size of image but still be clipped to the viewport of the UIScrollView only.
I can't seem to see any official say on this and if it is a bug has existed at least until iOS 13 (and is still in iOS 15)
Does anyone know if this is a known issue (Apple Engineers)?
Most code examples look like this https://stackoverflow.com/a/48590443/1735584
but there are also examples with drawInHierarchy and snapshotView which results in the same thing