Post

Replies

Boosts

Views

Activity

Reply to Attachment is displayed incorrectly
I've tested various options for custom attachment drawing, and the only one I can get to work consistently on macOS 15.0 Release Candidate is setting the image property of the text attachment. I'm using NSImage.init(size:flipped:drawingHandler:) to do custom drawing, similar to what I was previously doing in NSTextAttachmentCell.draw(withFrame:in:characterIndex:). I also set the bounds of the text attachment to adjust the position of the attachment, which I was previously doing with NSTextAttachmentCell.cellBaselineOffset(). The one thing I haven't been able to accomplish with this approach is changing the appearance of the attachment when it's selected. I also experimented with view-based text attachments, using NSTextAttachmentViewProvider. This worked well in an NSTextView, but in an NSTextField or NSSearchField, the custom view would only show when the text field was first responder. I can't find any clear documentation on how view-based text attachments are meant to be used, so I'm not sure if there's any way to work around that problem. I've filed a bug report on this issue, FB15109146.
Topic: UI Frameworks SubTopic: AppKit Tags:
Sep ’24
Reply to Use of the Expanded/Condensed SF Font Families in iOS 16
Thanks to the tip from @hacknicity, here's an example in Swift for UIKit: var descriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .largeTitle) let traits: [UIFontDescriptor.TraitKey:Any] = [.width: -1.0] descriptor = descriptor.addingAttributes([.traits: traits]) let uiFont = UIFont(descriptor: descriptor, size: descriptor.pointSize) This creates a narrow version of the "large title" text style. According to the header file, the width value should be a float between -1.0 to 1.0. -1.0 will give you a narrow width, 0.0 is a normal width, and 1.0 is wide. There are options between those values—for example 0.25 gave me a width that's just a bit more narrow than normal. It seems there's not a direct equivalent of UIFontDescriptor in SwiftUI. However, you can create a SwiftUI Font from a UIFont. Just add one more line to the example above: let font = Font(uiFont as CTFont) I imagine this will become easier to use in a later beta.
Topic: Design SubTopic: General Tags:
Jun ’22
Reply to When validating a receipt, what is the correct way to find the most recent transaction for an app with a single subscription?
I should have mentioned that this is happening after using the "Restore Purchases" button in my app. This calls the restoreCompletedTransactions() method on the default SKPaymentQueue. I then wait for paymentQueueRestoreCompletedTransactionsFinished() and send the receipt to my server for validation. Afterward I go through the items in transactions where the transactionState is restored or purchased and call finishTransaction() for each one. I did some testing, and it seems this is an important step in what's happening. If I validate the same receipt without restoring anything, I get consistent results. The transaction in latest_receipt_info is still not the most recent transaction—but it is the same transaction each time. When I discovered this, I thought I might be able to solve the problem by sorting the transactions by date before calling finishTransaction(). This doesn't seem to make a difference. It's possible I'm overlooking something in my code but it seems like simply calling restoreCompletedTransactions() jumbles the transactions and results in a random one being considered the "latest" according to the verifyReceipt endpoint. This post on Stack Overflow - https://stackoverflow.com/q/42312927/813247 is the closest I've found to anyone discussing similar behavior. I hadn't noticed it previously but I'm seeing the same thing—restoreCompletedTransactions() does change the transaction IDs. Seems surprising to me, but it's not a problem. Then I noticed that original_purchase_date is also changing—it's the current date and time! The purchase_date is the actual date of the purchase. That's backwards from what I would expect. But this at least makes sense now: according to this date it is the latest transaction. It seems like it's re-running all the transactions in an effectively random order and updating the purchase date as it goes. This still doesn't make sense to me, but I at least feel like I understand what's happening. The sole answer to that Stack Overflow post suggests using SKReceiptRefreshRequest instead of restoreCompletedTransactions(). My understanding was that these do not necessarily do the same thing, and restoreCompletedTransactions() should be done to make sure transactions appear on a new device, or after deleting and reinstalling the app. SKReceiptRefreshRequest is what you should use if the receipt file is invalid or missing. These seem like pretty distinct use cases that are backed up by the current documentation. There's also a reply here from someone at Apple - https://developer.apple.com/forums/thread/127923 suggesting the app won't pass app review if I rely on SKReceiptRefreshRequest for this. I think at this point I'm going to: Assume latest_receipt_info may contain more than one transaction in non-chronological order. I'll loop through each one and look for the latest expires_date_ms. This addresses my first two questions and seems like the safest approach. Assume that latest_receipt_info may not include the most recent purchase and check receipt.in_app as well. It's extra work, but due to the way purchases are restored it seems necessary to show my customers when their subscription expired. For my bonus questions I'm just going to assume I'm looking in the right place for the grace period and that pending_renewal_info should only contain a single item in my case. It shouldn't be hard to adjust these later as necessary. I feel pretty comfortable with this now, but if anyone has relevant knowledge I'd love to hear it.
Topic: App & System Services SubTopic: StoreKit Tags:
Aug ’20
Reply to How can I use conditional code for a new OS version while building with the current SDK?
I think @dimitri's answer is correct, and if at all possible it's definitely better to use a compiler check or preprocessor flag - https://stackoverflow.com/questions/38813906/swift-how-to-use-preprocessor-flags-like-if-debug-to-implement-api-keys/47395485#47395485 as a way to prepare in advance for a new SDK. This is safer because APIs can change during betas, and an approach like this will allow the compiler to make sure your code is correct when you build with the newer SDK. In my case I want to improve how a change in functionality is handled in the current version of my app, building with the current SDK. I was leaning toward using NSClassFromString() or responds(to:), both of which are available in Swift. But after thinking it over I don't think it makes sense to use those unless that's exactly what I need to check for—and in my case, it's not. I eventually found an NSHipster article titled "Swift System Version Checking" (which the forum won't allow me to link to for some reason). One of several options it suggests is isOperatingSystemAtLeast(_:) which seems like a good choice for handling a change in behavior rather than a change in API: if ProcessInfo.processInfo.isOperatingSystemAtLeast(OperatingSystemVersion(majorVersion: 14, minorVersion: 0, patchVersion: 0)) { 		print("Seems to be iOS 14!") }
Topic: Programming Languages SubTopic: Swift Tags:
Jul ’20
Reply to Where is the private DTK forum?
For me the tag doesn't show up in the prominent "View all tags >" page linked at the top of every page. I had to click on my avatar in the top-right corner (just below the search icon). Then a popup appears, with a "Developer Forums" section, and a link to "Universal App Quick Start". Of course as @designatednerd said, you'll also need access to the DTK for this to appear. In my case I made sure I'm signed into the same account I used to apply for the program, and to purchase the kit.
Topic: App & System Services SubTopic: Core OS Tags:
Jul ’20