Hi all,
I have a book club app I'm developing that utilizes SwiftData and Cloudkit. From what I've learned, the way to display lists that can update in real time across multiple devices is to retrieve an array of the model objects via the Query keyword then use a computed property to sort and filter the array to your liking, and reference that computed property when you need to display the list. This works, but it seems inefficient to grab every single object of a given model and sort / filter it each time.
The other method I've been trying was, for example, after the user selects a Book object that comes from a queried list populated via the method above, to pass that Book object through the program so I can access its properties to display their lists (and it should work right because that initial book property came directly from a queried array of Books?).
For instance, a Book object has an array of Readers. After a user selects a Book, I can pass that Book object to the ReaderView class and display itsreaders array, and it should update in real time on CloudKit since that Book object came from a queried Books array. The benefit of this is you don't have to do as much sorting and filtering. But unfortunately, I've had mixxed results doing it this way, and it seems that the further you get away from the original object, the less success I've had getting it to update in real time. For instance, if I try to access a Reader objects Comments array property, it might not work.
Anyways, I'm wondering if I should generally just keep it simple and stick to the first method I mentioned, or if there is a pattern that people generally follow?
Post
Replies
Boosts
Views
Activity
Hi all,
I have a SwiftUI-SwiftData-CloudKit app that has a TextField. I would like to make it so that after a user types in text, it will update the TextField on another device via CloudKit. I have the following code:
{
private let comment:Comment
@Query private var comments: [Comment]
@State private var text: String = ""
@State private var userInput = ""
private var filteredComment: Comment?
{
if let comment = self.comments.first(where: { $0 == self.comment })
{
return comment
}
else
{
return nil
}
}
init(comment: Comment)
{
self.comment = comment
}
var body: some View
{
VStack
{
if let filteredComment = self.filteredComment
{
TextField("", text: self.$text)
.onAppear()
{
self.text = filteredComment.text
}
.onChange(of: self.text)
{
filteredComment.text = text
}
}
}
}
}
This code actually works fine and will update to another device via CloudKit when a user exits out of the view and then reloads it. But I would like for it to update to the TextField after the user finishes typing or while they're typing. Weirdly, it will update on the fly in another screen I have in the app that displays the same text in a list. I've tried saving the modelContext after loading self.filteredComment and it makes no difference. Anyone know what's going on here? Thanks.
Hi, in my app I don't use PencilKit anywhere, yet I keep getting the following crash:
Pencil Kit Crash.txt
I don't even know where to start in debugging this. Could this be a bug within UIKit? It obviously only occurs in iPad devices and so far not in iOS16, but that may just be because of sample size. Do I need to handle touches differently for when a user uses an Apple Pen? Any help is appreciated. Thanks.
Hi,
Using UITextInput, I'm gathering text from the keyboard to display in a custom text view. The user is only allowed to enter 10 characters in the lite version of my app and if that number is exceeded, the "shouldChangeTextInRange" method posts an alert asking the user to upgrade rather than insert the text in the text view.
In iOS16, I'm noticing when I test with swipe typing and the character limit is exceeded, when I try to post the alert over the keyboard the app locks up and I get the following in the console:
-[UIKeyboardTaskQueue lockWhenReadyForMainThread] timeout waiting for task on queue.
Keyboard queue task timeout detected
You can see what I mean in the following video:
https://vimeo.com/752856336
The first part of the video is on the iOS15 simulator and it works, the alert pops up successfully. The second half is the iOS16 simulator where it freezes when I try to post the alert.
I'm guessing that the suggestions toolbar that appears when you swipe type is what's causing this.
Going to report this as a bug to Apple but was wondering if anyone might know a workaround for this? Thanks!
Hi, I have constructed a custom TextView built on CoreText for the purpose of allowing a user to enter text into odd shapes. In creating the CTTextFrame, I've noticed that when a new line character is added and a new line is created, the height of the new line is much smaller then the other lines.
This is despite the fact that I'm adding the same font and size attributes to the newline character when I append it to the NSMutableAttributedString.
Here is the code that's producing this:
NSMutableAttributedString *textFramesetterText = [self.text mutableCopy];
//insert buffer area at the top and bottom of the rectangle
[textFramesetterText insertAttributedString:@" \n" atIndex:0];
[textFramesetterText appendAttributedString:@"\n "];
CTFramesetterRef textFramesetter = CTFramesetterCreateWithAttributedString((__bridge CFMutableAttributedStringRef)textFramesetterText);
//calculate the width and height based on the text
CGFloat width = [self textFrameHeightForWidth: MaxTextWidth maxTextHeight:self.maxTextHeight textFramesetter:textFramesetter textFrameSetterText:textFramesetterText];
CGFloat height = [self textFrameWidthForHeight: size.height maxTextWidth:MaxTextWidth textFramesetter:textFramesetter textFrameSetterText:textFramesetterText];
CTFrameRef textFrame = [self newTextFrameForFrame:CGRectMake(0,0,width,height) textFramesetter:textFramesetter];
self.textFrame = textFrame;
CFRelease(textFrame);
CFRelease(textFramesetter);
I know this has been a issue with CTTextFrame for a long time and I'm wondering if there is any way to fix this. My workaround right now is to add a space after the newline character, but this can get messy. Any help would be appreciated. Thanks.
Hi,
In my app, I have a custom text view so I've implemented the UITextInput protocol to help me gather text from the keyboard.
I'm getting a strange memory leak when the method textInRange is called:
- (NSString *)textInRange:(UITextRange *)range
{
if (self.keyboardInputAccessoryMenuView)
{
IndexedRange *r = (IndexedRange *)range;
NSString *textString = self.labelView.labelTextView.text.string;
if ([self rangeExists: r.range inString:textString])
{
return ([textString substringWithRange:r.range]);
}
else
{
return nil;
}
}
else
{
return nil;
}
}
"text" is an NSMutableAttributedString. The error exists at the following line:
return ([textString substringWithRange:r.range]);
This is the crash log I'm getting:
Crashed: com.apple.main-thread
0 libsystem_platform.dylib 0x1e086f754 _platform_memmove + 340
1 CoreFoundation 0x1942671cc __CFStringCreateImmutableFunnel3 + 2588
2 CoreFoundation 0x19426b8a4 CFStringCreateWithSubstring + 524
3 CoreFoundation 0x1941b24e0 -[__NSCFString substringWithRange:] + 164
4 Label Maker 0x102166604 -[LabelWindowView textInRange:] + 968 (LabelWindowView.m:968)
5 UIKit 0x1e0b4bdb8 -[UITextInputUIResponderAccessibility accessibilityValue] + 172
6 UIAccessibility 0x1a85f7c40 -[NSObject(AXPrivCategory) _accessibilityPotentiallyAttributedValueForNonAttributedSelector:attributedSelector:] + 284
7 UIAccessibility 0x1a85f7ebc -[NSObject(AXPrivCategory) _accessibilityAXAttributedValue] + 48
8 UIAccessibility 0x1a85fdd10 -[NSObject(AXPrivCategory) _iosAccessibilityAttributeValue:] + 5516
9 UIAccessibility 0x1a862ebf8 _accessibilityAttributesForObject + 412
10 UIAccessibility 0x1a862e384 -[NSObject(UIAccessibilityAutomation) _accessibilityUserTestingSnapshotDescendantsWithAttributes:maxDepth:maxChildren:maxArrayCount:honorsModalViews:] + 888
11 UIAccessibility 0x1a862ff8c -[NSObject(UIAccessibilityAutomation) _accessibilityUserTestingSnapshotWithOptions:] + 1112
12 UIAccessibility 0x1a85fb8b0 -[NSObject(AXPrivCategory) _iosAccessibilityAttributeValue:forParameter:] + 11464
13 UIKit 0x1e0abbae0 -[UIApplicationAccessibility _iosAccessibilityAttributeValue:forParameter:] + 308
14 UIAccessibility 0x1a85d6648 _copyParameterizedAttributeValueCallback + 408
15 AXRuntime 0x1b3c50dd8 ___AXXMIGCopyParameterizedAttributeValue_block_invoke + 64
16 AXRuntime 0x1b3c505e4 _handleNonMainThreadCallback + 68
17 AXRuntime 0x1b3c50c60 _AXXMIGCopyParameterizedAttributeValue + 388
18 AXRuntime 0x1b3c9f074 _XCopyParameterizedAttributeValue + 392
19 AXRuntime 0x1b3c60200 mshMIGPerform + 272
20 CoreFoundation 0x194245fe8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 60
21 CoreFoundation 0x194245378 __CFRunLoopDoSource1 + 596
22 CoreFoundation 0x19423f08c __CFRunLoopRun + 2360
23 CoreFoundation 0x19423e21c CFRunLoopRunSpecific + 600
24 GraphicsServices 0x1abe0a784 GSEventRunModal + 164
25 UIKitCore 0x196c7eee8 -[UIApplication _run] + 1072
26 UIKitCore 0x196c8475c UIApplicationMain + 168
27 Label Maker 0x102140100 main + 15 (main.m:15)
28 libdyld.dylib 0x193efe6b0 start + 4
This code in this function works most of the time, but occasionally I get this bug out of nowhere and can't recreate it.
Can anyone offer any insight on this?
Hi, I've recently added PHPicker to my app and have gotten some returns and low sales that may or may not be a result of the change and just want to make sure my implementation is correct.
I'm concerned about the pickerDidFinishPicking function in particular. Here is my simple implementation that allows the user to select one image from their photo library:
(void) presentPHPickerController
{
PHPickerConfiguration *config = [[PHPickerConfiguration alloc] init];
config.filter = [PHPickerFilter imagesFilter];
PHPickerViewController *pickerViewController = [[PHPickerViewController alloc] initWithConfiguration:config];
pickerViewController.delegate = self;
[self.navigationController presentViewController:pickerViewController animated:YES completion:nil];
}
(void) picker:(PHPickerViewController *)picker didFinishPicking:(NSArrayPHPickerResult * *)results
{
PHPickerResult *result = [results firstObject];
if (result)
{
[result.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(__kindof idNSItemProviderReading _Nullable object, NSError * _Nullable error)
{
dispatch_async(dispatch_get_main_queue(),
^{
[picker dismissViewControllerAnimated:YES completion:nil];
if (!error)
{
/*do something with the image*/
}
else
{
/*present alert*/
}
});
}];
}
else
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
}
My main concern is dismissing the picker on the main thread after the image has been loaded successfully. In most examples, I see people dismiss the picker at the very start of this function. I prefer to have the behavior where it gets dismissed after the user selects the photo however. Is there any issue with doing this?
My other question is, if the loadObjectOfClass executes successfully without error, is it guarenteed there will be a UIImage in "object"?
Thanks for the help.