Post

Replies

Boosts

Views

Activity

trailingSwipeActionsConfigurationProvider causes shadow effect on UICollectionViewListCell gone
Currently, I have achieve shadow and corner effect for UICollectionViewListCell, using the following code. UICollectionViewListCell class NoteCell: UICollectionViewListCell { override func awakeFromNib() { super.awakeFromNib() initShadow() initCorner() } private func updateShadowColor() { // Determine the shadow color based on the current interface style let shadowUIColor = UIColor.label self.layer.shadowColor = shadowUIColor.cgColor } private func initShadow() { // https://www.hackingwithswift.com/example-code/uikit/how-to-add-a-shadow-to-a-uiview self.layer.shadowOpacity = 0.3 self.layer.shadowOffset = CGSize(width: 0.5, height: 0.5) self.layer.shadowRadius = 2 self.layer.masksToBounds = false self.updateShadowColor() // Remove the following two lines if you experience any issues with shadow rendering: self.layer.shouldRasterize = true self.layer.rasterizationScale = UIScreen.main.scale } private func initCorner() { var backgroundConfig = UIBackgroundConfiguration.listPlainCell() backgroundConfig.backgroundColor = .systemBackground backgroundConfig.cornerRadius = 16 self.backgroundConfiguration = backgroundConfig } layout private func layoutConfig() -> UICollectionViewCompositionalLayout { let layout = UICollectionViewCompositionalLayout { section, layoutEnvironment in var config = UICollectionLayoutListConfiguration(appearance: .plain) config.headerMode = .none config.footerMode = .none config.showsSeparators = false config.headerTopPadding = 0 config.backgroundColor = nil config.trailingSwipeActionsConfigurationProvider = { [weak self] indexPath in guard let self = self else { return nil } // Knowing what we are tapping at. var snapshot = dataSource.snapshot() let sectionIdentifier = snapshot.sectionIdentifiers[indexPath.section] let itemIdentifiers = snapshot.itemIdentifiers(inSection: sectionIdentifier) let itemIdentifier: NoteWrapper = itemIdentifiers[indexPath.item] let deleteHandler: UIContextualAction.Handler = { action, view, completion in completion(true) // TODO: //snapshot.reloadItems([itemIdentifier]) } let deleteAction = UIContextualAction(style: .normal, title: "Trash", handler: deleteHandler) var swipeActionsConfiguration = UISwipeActionsConfiguration(actions: [ deleteAction, ]) deleteAction.image = UIImage(systemName: "trash") deleteAction.backgroundColor = UIColor.systemRed swipeActionsConfiguration.performsFirstActionWithFullSwipe = false return swipeActionsConfiguration } // https://developer.apple.com/forums/thread/759987 let layoutSection = NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) layoutSection.interGroupSpacing = 16 // Distance between item. layoutSection.contentInsets = NSDirectionalEdgeInsets( top: 16, // Distance between 1st item and its own header. leading: 16, bottom: 16, // Distance of last item and other header/ bottom edge. trailing: 16 ) return layoutSection } return layout } This is the outcome. However, when I perform swipe action, the shadow effect is gone. Do you have any idea how I can resolve such? Thanks.
0
0
156
4w
UILabel Attributed Text Anomaly: Unexpected Strikethrough When Setting Text Property in Swift
The following code, will create a red color text, without strike-through. class ViewController: UIViewController { @IBOutlet weak var label: UILabel! override func viewDidLoad() { super.viewDidLoad() let text = "Hello World" let textCount = text.count let fullRange = NSRange(location: 0, length: textCount) var attributedText = NSMutableAttributedString(string: text) attributedText.addAttribute(.foregroundColor, value: UIColor.green, range: fullRange) attributedText.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: fullRange) label.attributedText = attributedText attributedText = NSMutableAttributedString(string: text) attributedText.addAttribute(.foregroundColor, value: UIColor.red, range: fullRange) attributedText.removeAttribute(NSAttributedString.Key.strikethroughStyle, range: fullRange) label.attributedText = attributedText } } However, if I trigger label.text in between, it will cause the following strange behavior : A red color text, with strike-through created at the end of function. class ViewController: UIViewController { @IBOutlet weak var label: UILabel! override func viewDidLoad() { super.viewDidLoad() let text = "Hello World" let textCount = text.count let fullRange = NSRange(location: 0, length: textCount) var attributedText = NSMutableAttributedString(string: text) attributedText.addAttribute(.foregroundColor, value: UIColor.green, range: fullRange) attributedText.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: fullRange) label.attributedText = attributedText // Why this will cause a red color text, with strike-through created at the end of function? label.text = text attributedText = NSMutableAttributedString(string: text) attributedText.addAttribute(.foregroundColor, value: UIColor.red, range: fullRange) attributedText.removeAttribute(NSAttributedString.Key.strikethroughStyle, range: fullRange) label.attributedText = attributedText } } Does anyone what is the reason behind this behavior, and how I can avoid such? Thank you.
0
0
221
Aug ’24
Understanding Policies on Account Associations: Google vs. Apple
Google has a very strict policy regarding "associated previously terminated accounts." This means that if you are associated with another previously banned developer, you will be banned too. For instance : https://www.reddit.com/r/androiddev/comments/9mpyyi/google_play_developer_account_terminated_due_to/ Does Apple have a similar policy? Recently, I was considering providing read-only access to an external party on App Store Connect. However, I am concerned that it might trigger the same risk. Therefore, I am wondering if Apple has such a policy. Thanks.
0
0
265
Jul ’24
Optimizing Sorting and Order Management in CoreData
Sorting is an important feature in my app. I am using integers to represent the ordering sequence. Items: A, B, D, E, H Order number: 0, 1, 2, 3, 4 When I insert a new item "C", here's the outcome: Items: A, B, C, D, E, H Order number: 0, 1, 2, 3, 4, 5 Here's the write operation required on existing order numbers: D: 2 -> 3 E: 3 -> 4 H: 4 -> 5 I wish to reduce the number of write operations because CoreData is pretty slow at writing. The problem becomes more significant when my users start to have a few thousand items in CoreData. Here's my current workaround: leaving gaps between each order number. For instance: Items: A, B, D, E, H Order number: 0, 10, 20, 30, 40 When I insert a new item "C", here's the outcome: Items: A, B, C, D, E, H Order number: 0, 10, 11, 20, 30, 40 No write operations are required on existing order numbers. Every 1 or 2 weeks, when my users close the app, I run background tasks to re-arrange the gaps between order numbers so that when users insert new items, fewer existing order numbers will be affected. Items: A, B, C, D, E, H Order number: 0, 10, 20, 30, 40, 50 Since sorting is pretty common, I was thinking some of you might have a better idea on how to reduce write operations on existing order numbers. If you have a better idea, do you mind to share it with us? Thanks.
1
0
297
Jul ’24
When using NSCollectionLayoutSection.list, how to specific header height and cell item height?
I am using NSCollectionLayoutSection.list as follow. private func layoutConfig() -> UICollectionViewCompositionalLayout { let layout = UICollectionViewCompositionalLayout { section, layoutEnvironment in var config = UICollectionLayoutListConfiguration(appearance: .plain) config.headerMode = .supplementary config.footerMode = .none config.showsSeparators = false config.headerTopPadding = 0 // https://developer.apple.com/forums/thread/759987 let layoutSection = NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) layoutSection.interGroupSpacing = 0 layoutSection.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) if let header = layoutSection.boundarySupplementaryItems.first(where: { $0.elementKind == UICollectionView.elementKindSectionHeader }) { header.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) } return layoutSection } return layout } We provide our own custom header view and cell item view. Header View class HideShowHeader: UICollectionViewListCell { override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize { // Ensure the cell fills the width of the collection view let size = CGSize( width: targetSize.width, height: 80 ) print(">>>> size \(size)") return size } } Cell Item View class TodoCell: UICollectionViewListCell { override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func systemLayoutSizeFitting(_ targetSize: CGSize) -> CGSize { // Ensure the cell fills the width of the collection view let size = CGSize( width: targetSize.width, height: 80 ) return size } } We would like to fine-tune the height of header and cell item. However, override systemLayoutSizeFitting doesn't work. May I know, when using NSCollectionLayoutSection.list, how to specific header height and cell item height? Thanks.
0
1
220
Jul ’24
Specifying Item Spacing in UICollectionLayoutListConfiguration
Currently, I am using UICollectionViewCompositionalLayout to achieve the following list layout with spacing: We were thinking of trying out UICollectionLayoutListConfiguration due to its ability to support swipe actions. We would like to specify the spacing between each item. However, I do not find a way to specify item spacing in UICollectionLayoutListConfiguration. Does UICollectionLayoutListConfiguration not support item spacing, or have I missed something? Thanks.
1
0
406
Jul ’24
Customizing Drop Location View in UICollectionView Drag and Drop
Currently, this is how I implement the drag and move operation: collectionView.beginInteractiveMovementForItem collectionView.updateInteractiveMovementTargetPosition collectionView.endInteractiveMovement The outcome looks like the following: However, what I would like to achieve is the ability to customize the view of the "drop" location. For instance, in the following example, a red line is drawn at the target drop location: In this example, a transparent rectangle is drawn at the target drop location: May I know how these apps achieve such an effect? Thanks.
0
0
261
Jul ’24
How to deal with Guideline 2.1 - Information Needed (App Tracking Transparency framework related)
My app, which only shows ads one day after it is first launched, keeps being rejected due to Guideline 2.1 - Information Needed (App Tracking Transparency framework related). Here is the rejection message from Apple: Guideline 2.1 - Information Needed We're looking forward to completing our review, but we need more information to continue. Your app uses the AppTrackingTransparency framework, but we are unable to locate the App Tracking Transparency permission request when reviewed on iOS 17.5.1. Next Steps Please explain where we can find the App Tracking Transparency permission request in your app. The request should appear before any data is collected that could be used to track the user. If you've implemented App Tracking Transparency but the permission request is not appearing on devices running the latest operating system, please review the available documentation and confirm App Tracking Transparency has been correctly implemented. If your app does not track users, update your app privacy information in App Store Connect to not declare tracking. You must have the Account Holder or Admin role to update app privacy information. We have provided a detailed step-by-step guide to trigger the App Tracking Transparency. We also attached videos demonstrating how to adjust the date to one day ahead in order to show the ads. Here is our reply: Dear Reviewer, *** will start displaying ads one day after the app is first launched. To see the App Tracking Transparency permission request and subsequent ads, please follow these steps: 1. Launch *** for the first time. 2. Close and completely exit the *** app. 3. Adjust the date on your device to one day ahead. 4. Re-launch ***. You will see the App Tracking Transparency permission request. For a visual guide, please refer to the attached videos: https://youtube.com/shorts/07qsYuFkPBY - Demonstrates when the user allows tracking. https://youtube.com/shorts/voQfgjAN7h0 - Demonstrates when the user does not allow tracking. If you need further explanation, please contact me at +xxxx-xxxxxxx. Thank you. P.S. I frequently receive similar inquiries with each submission of my app. Could you please add a note to my app to prevent this recurring issue in future reviews? Thank you for your attention. However, Apple continues to reject our update, despite our clear instructions for showing App Tracking Transparency. Do you have any suggestions on what we can do next? Thank you.
2
0
666
Jul ’24
Implementing Undo/Redo Feature in UITextView with IME Support
Currently, we are implementing an undo/redo feature in UITextView. However, we cannot use the built-in UndoManager in UITextView because we have multiple UITextView instances inside a UICollectionView. Since UICollectionView recycles UITextView instances, the same UITextView might be reused in different rows, making the built-in UndoManager unreliable. The shouldChangeTextIn method in UITextViewDelegate is key to implementing undo/redo functionality properly. Here is an example of our implementation: extension ChecklistCell: UITextViewDelegate { func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { // Get the current text let s = textView.text ?? "" // Get the starting position of the change let start = range.location // Get the number of characters that will be replaced let count = range.length // Get the number of characters that will be added let after = text.count print(">>>> The current text = \"\(s)\"") print(">>>> The starting position of the change = \(start)") print(">>>> The number of characters that will be replaced = \(count)") print(">>>> The number of characters that will be added = \(after)") print(">>>>") if let delegate = delegate, let checklistId = checklistId, let index = delegate.checklistIdToIndex(checklistId) { delegate.attachTextAction(s: s, start: start, count: count, after: after, index: index) } return true } } Working scene behind the UITextViewDelegate However, this implementation does not work well with non-English input using an IME. When using an IME, there is an intermediate input before the final input is produced. For example, typing "wo" (intermediate input) produces "我" (final input). Currently, UITextViewDelegate captures both "wo" and "我". UITextViewDelegate captures both "wo" and "我" Is there a way to ignore the intermediate input from IME and only consider the final input? In Android, we use the beforeTextChanged method in TextWatcher to seamlessly ignore the intermediate input from IME and only consider the final input. You can see this in action in this Android captures only "我" Is there an equivalent way in iOS to ignore the intermediate input from IME and only take the final input into consideration?
0
0
308
Jun ’24
In-App Purchase Review Delaying App Release - Next Steps?
Our submitted binary app version has been approved by Apple reviewers. It's currently pending Developer Release. However, our in-app purchase, which was submitted at the same time, is still under review. Since the newly added in-app purchase hasn't been approved yet, we've decided to hold off on releasing the binary app version. Should we just wait for Apple to approve the in-app purchase, or are there any other recommended actions? Thank you.
2
0
484
Jun ’24
What are some other actionable items I can do, so that I can get through "Guideline 4.3(a) - Design - Spam" app update rejection?
I have an app which is in the app store since 2022. It is an app with combined features of note taking, todo list and calendar. My most recent app update is rejected with the following message. Guideline 4.3(a) - Design - Spam We noticed your app shares a similar binary, metadata, and/or concept as apps submitted to the App Store by other developers, with only minor differences. Submitting similar or repackaged apps is a form of spam that creates clutter and makes it difficult for users to discover new apps. Next Steps Since we do not accept spam apps on the App Store, we encourage you to review your app concept and submit a unique app with distinct content and functionality. Resources Some factors that contribute to a spam rejection may include: Submitting an app with the same source code or assets as other apps already submitted to the App Store Creating and submitting multiple similar apps using a repackaged app template Purchasing an app template with problematic code from a third party Submitting several similar apps across multiple accounts Learn more about our requirements to prevent spam in App Review Guideline 4.3(a). Support Reply to this message in your preferred language if you need assistance. If you need additional support, use the Contact Us module. Consult with fellow developers and Apple engineers on the Apple Developer Forums. Help improve the review process or identify a need for clarity in our policies by suggesting guideline changes. I reply the reviewer with the following message. Hi, I am writing to appeal the rejection of my app, ***. I would like to emphasize the unique aspects of *** that distinguish it from other apps in the market: Integrated Functionality: Unlike most apps that are standalone note-taking, to-do, or calendar apps, *** uniquely combines all three functions into a single app. Extensive Calendar Features: *** includes a comprehensive calendar feature covering holidays in 250 countries and 3,680 states and provinces, a rare and valuable feature. Chinese Lunar Calendar: Our app includes a Chinese Lunar Calendar, which is highly appreciated in the Taiwanese market, adding a culturally specific feature not commonly found in other apps. Organizational Tools: *** allows unlimited tabs and colors for organizing notes, surpassing many competitors who offer limited color options. Flexible Viewing and Sorting Modes: Users can choose from four viewing modes (Grid, Compact Grid, List, Compact List) and five sorting modes (Modified Time, Created Time, Alphabet, Color, Check, Reminder), enhancing the user experience by providing flexibility and customization. No Character Limit: Our design supports notes of any length without character limitations, unlike many apps that impose restrictions. Organized To-Do Lists: Completed to-do items are automatically moved to the bottom, keeping the list clean and organized, a feature that sets us apart from other apps. Rich Attachments: *** supports unlimited picture attachments, drawing attachments, and voice recordings for notes, offering more versatility than many other apps. Advanced Security: *** offers 3 different kinds of password lock mechanisms to protect note privacy, ensuring users have multiple options for securing their information. Powerful Reminders: Our app includes highly customizable reminders that can repeat daily, weekly, monthly, or yearly, making it easy for users to stay on top of their tasks and appointments. Due to the character limits of this form, I cannot list all the unique features of ***. Please refer to our product description for a comprehensive overview. We are proud of our 5k user reviews with an average rating of 4.8, reflecting user satisfaction with ***'s unique features. Here's are some of the recent reviews. (United states only. Please kindly contact me to obtain full list of the reviews) by ??? – Jun 14, 2024 omg i cannot explain how much i love *** like unlike the boring notes app this one is actually fun to use and rlly easy and i rlly like the fonts, color, to do list, calandar that can remind you like every day, week, month, and year like omg?!?!? i love *** and this app is going in like my "I 💖U" folder like tysm for making *** idk what i would do without it like omg tysm i cant explain in words how much i love it💖💖💖💖💖💖💖💖💖💖💖💖💖💖 by ??? – May 12, 2024 I love it sooo much I give it a 5 because there is a password so no one can look by ??? – Apr 30, 2024 Perfect app. All in one by ??? – Mar 26, 2024 I just downloaded this app a few days ago and I love it!! 😃 Up til recently I ALWAYS used paper sticky notes that I would have on my desk - and the reason why is because I could see everything all at once at all times; it’s very convenient - but it also produces clutter and anxiety because every subject is all in one place. *** fixed that!! 😀 With tabs and the list or grid view mode, I can have more organization of subjects and still see almost everything all at once! I love it! 🤩 suggestion I would really love to have more format options for the text! 🙂 Like a button to indent, and be able to have sub notes with points, dashes, or numbers. It makes everything look more tidy and neat. Thank you for this wonderful app! 😆 I am available at 123-456-789 to discuss further and provide additional detail. Thank you. Till to date, I haven't received reply from the reviewer. May I know, what are some other actionable items I can do, so that I can get through "Guideline 4.3(a) - Design - Spam" app update rejection? Thank you so much!
1
0
714
Jun ’24
Troubleshooting Core Data Lightweight Migration: A Real-World Challenge
In my recent endeavor, I aimed to introduce new Fetch Index Elements to the Core Data model of my iOS application. To achieve this, I followed a process of lightweight migration, detailed as follows: Navigate to Editor > Add Model Version to create a new version of the data model. Name the new version with a sequential identifier (e.g., MyAppModelV3.xcdatamodel) based on the naming convention of previous models. Select the newly created version, MyAppModelV3.xcdatamodel, as the active model. Mark this new version as the "Current" model in the Xcode properties panel on the right. In the new version of the model, MyAppModelV3.xcdatamodel, and add the new Fetch Index Elements there. Also, insert "v3" in the Versioning Hash Modifier field of affected entity, to indicate this modification. Upon reflection, I realized that creating a new version of the xcdatamodel might not have been necessary for this particular case. However, it appears to have caused no adverse effects on the application's functionality. During testing, I executed the application in a simulated environment, initially running an older version of the app to inspect the database content with SQLite DB Browser. I then upgraded to the latest app version to verify that the migration was successfully completed without causing any crashes. Throughout this testing phase, I employed the -com.apple.CoreData.MigrationDebug 1 flag to monitor all SQL operations, ensuring that indexes were appropriately dropped and recreated for the affected entity. Following thorough testing, I deployed the update to production. The majority of users were able to upgrade to the new app version seamlessly. However, a small fraction reported crashes at startup, indicated by the following error message: Fatal error: Unresolved error Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={NSUnderlyingError=0x2820ad3e0 {Error Domain=NSCocoaErrorDomain Code=134100 "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store." UserInfo={metadata={ NSPersistenceFrameworkVersion = 1338; NSStoreModelVersionChecksumKey = "qcPf6+DfpsPrDQ3j1EVXcBIrFe1O0R6IKd30sJf4IrI="; NSStoreModelVersionHashes = { NSAttachment = {length = 32, ... Strangely, the only way I could replicate this issue in the simulator was by running the latest version of the app followed by reverting to an older version, a scenario unlikely to occur in a real-world setting. This raises the question: How could this situation arise with actual users, considering they would typically move from an old to a new version rather than the reverse? I am reaching out to the community for insights or advice on this matter. Has anyone else encountered a similar problem during the Core Data migration process? How did you resolve it?
1
1
598
Mar ’24
Not able login to simulator using the newly created sandbox account
I wish to login simulator using a sandbox account so that I can test on in-app purchase and subscription. I have created a new apple id account using a new email. I have confirmed the new apple id + password is correct, by login into https://appleid.apple.com/#!&page=signin I also added the new apple id account into App Store Connect as sandbox tester - However, I am still not able login to simulator. I am keep getting error - "Username or password is incorrect" You can see in the simulator background. I can login to https://appleid.apple.com/#!&page=signin using the new apple id + password via web browser. But, I am not sure why I am not able login into the simulator itself. Can anyone assist me on this? Thank you.
2
3
610
Mar ’24