After typing anything in a custom text field with undo support, when opening the Edit menu, the undo item is disabled. It seems that setting translatesAutoresizingMaskIntoConstraints=false, a formatter, allowsEditingTextAttributes=true and calling invalidateIntrinsicContentSize() in textDidChange(_:) causes this behaviour.
Is this expected, or is there a workaround?
Here is the code:
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
@IBOutlet weak var textField: NSTextField!
override func loadView() {
view = NSView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
let textField = MyTextField()
textField.frame = CGRect(x: 0, y: 0, width: 100, height: 20)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.formatter = MyFormatter()
textField.allowsEditingTextAttributes = true
view.addSubview(textField)
}
}
class MyTextField: NSTextField {
override func textDidChange(_ notification: Notification) {
super.textDidChange(notification)
super.invalidateIntrinsicContentSize()
}
}
class MyFormatter: Formatter {
override func string(for obj: Any?) -> String? {
return obj as? String
}
override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
obj?.pointee = string as NSString
return true
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm trying to implement a text field in a table view that automatically adjusts its height to fit the contained text. My current implementation adjusts its intrinsicContentSize in textDidChange(_:). Unfortunately, NSCell.cellSize(forBounds:) doesn't seem to return the correct height unless setting attributedStringValue and allowsEditingTextAttributes = true for the NSTextField.
Is this expected, or is there a workaround?
Here is the code:
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
var asdf = "asdf fjdskalöf öf fjkldösa jfklödsa kfljsaödkfj klsdajf kldöasj flkjsdöa fkljasö flkjsa öj "
override func loadView() {
view = NSView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
let scrollView = NSScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
let tableView = NSTableView()
tableView.usesAutomaticRowHeights = true
tableView.addTableColumn(NSTableColumn())
tableView.dataSource = self
tableView.delegate = self
scrollView.documentView = tableView
view.addSubview(scrollView)
NSLayoutConstraint.activate([scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
}
func numberOfRows(in tableView: NSTableView) -> Int {
return 1
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let view = NSTableCellView()
let text = AutoSizingTextField()
text.translatesAutoresizingMaskIntoConstraints = false
text.cell?.wraps = true
// uncommenting the next 2 lines and commenting out the line after them solves the issue
// text.attributedStringValue = NSAttributedString(string: asdf, attributes: [.font: text.font!, .foregroundColor: NSColor.labelColor])
// text.allowsEditingTextAttributes = true
text.stringValue = asdf
view.addSubview(text)
NSLayoutConstraint.activate([text.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20), text.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), text.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20), text.widthAnchor.constraint(equalToConstant: 200)])
return view
}
}
class AutoSizingTextField: NSTextField {
override var intrinsicContentSize: NSSize {
var size = super.intrinsicContentSize
guard let cell = cell else {
return size
}
var frame = frame
frame.size.height = .infinity
size.height = cell.cellSize(forBounds: frame).height
NSLog("intrinsicContentSize \(size)")
return size
}
override func textDidChange(_ notification: Notification) {
super.textDidChange(notification)
invalidateIntrinsicContentSize()
needsLayout = true
layoutSubtreeIfNeeded()
}
override func layout() {
invalidateIntrinsicContentSize()
super.layout()
}
}
When building the code below, two compiler errors appear in AppDelegate.swift:
Value of type 'Slice<MyCollection<MySubCollection>>' has no member 'url'
No exact matches in call to instance method 'remove'
When moving the first 2 classes in ViewController.swift to AppDelegate.swift, the issues go away. Is this expected, or a bug?
// AppDelegate.swift
//
import Cocoa
@main
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
var collection: MyCollection<MySubCollection>!
let a = collection.first!.url!
var subCollection: MySubCollection!
collection.remove(subCollection)
}
}
//
// ViewController.swift
//
import Cocoa
class MyCollection<Element>: MyCollectionProtocol {
var elements = [Element]()
}
class MySubCollection: MyCollectionProtocol {
var elements = [String]()
var url: URL?
}
protocol MyCollectionProtocol: AnyObject, Collection where Index == Int {
associatedtype Element
var elements: [Element] { get set }
}
extension MyCollectionProtocol {
var startIndex: Index {
return elements.startIndex
}
var endIndex: Index {
return elements.endIndex
}
subscript(position: Index) -> Element {
return elements[position]
}
func index(after i: Index) -> Index {
return elements.index(after: i)
}
}
extension MyCollectionProtocol where Element == String {
func remove(_ element: Element) {
}
}
extension MyCollectionProtocol where Element: MyCollectionProtocol {
func remove(_ element: Element) {
}
}
I see that one can get all app categories, but I don't see a way of getting all supported screenshot display types and app preview types. Is this possible and if not, is there some way of getting all supported types without having to download the API specification?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect API
Tags:
App Store Connect API
When uploading app screenshots, I have to provide a sourceFileChecksum and uploaded flag: https://developer.apple.com/documentation/appstoreconnectapi/appscreenshotupdaterequest/data/attributes
But that's not the case for app event screenshots, I only have to provide the uploadedflag: https://developer.apple.com/documentation/appstoreconnectapi/appeventscreenshotupdaterequest/data/attributes
The same is true for app previews and app event video clips.
Why is this different?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect API
Tags:
App Store Connect API
When I open an iOS app in the App Store Connect website and disclose the Apple Watch section, it reads Apple Watch Ultra, Series 8, 6, 3, but the documentation for the API lists different versions:
APP_WATCH_ULTRA
APP_WATCH_SERIES_7
APP_WATCH_SERIES_4
APP_WATCH_SERIES_3
So the Watch Series don't seem to match.
There is a similar issue with iPad Pro. The website reads iPad Pro (6th Gen) 12.9" Display and iPad Pro (2nd Gen) 12.9" Display, but the API reads
APP_IPAD_PRO_3GEN_129
APP_IPAD_PRO_129
So again the Gen values don't seem to match.
How should I interpret these values?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
Tags:
App Store Connect
App Store Connect API
The following code should produce 6 spinning progress indicators of varying sizes: 3 indeterminate and 3 determinate ones. The first two of the 3 determinate ones are either entirely or partially cut off, which doesn't happen with the indeterminate ones. What's the problem?
var progress = NSProgressIndicator(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
progress.style = .spinning
view.addSubview(progress)
progress = NSProgressIndicator(frame: CGRect(x: 50, y: 0, width: 24, height: 24))
progress.style = .spinning
view.addSubview(progress)
progress = NSProgressIndicator(frame: CGRect(x: 100, y: 0, width: 32, height: 32))
progress.style = .spinning
view.addSubview(progress)
progress = NSProgressIndicator(frame: CGRect(x: 150, y: 0, width: 16, height: 16))
progress.style = .spinning
progress.isIndeterminate = false
progress.doubleValue = 50
progress.maxValue = 100
view.addSubview(progress)
progress = NSProgressIndicator(frame: CGRect(x: 200, y: 0, width: 24, height: 24))
progress.style = .spinning
progress.isIndeterminate = false
progress.doubleValue = 50
progress.maxValue = 100
view.addSubview(progress)
progress = NSProgressIndicator(frame: CGRect(x: 250, y: 0, width: 32, height: 32))
progress.style = .spinning
progress.isIndeterminate = false
progress.doubleValue = 50
progress.maxValue = 100
view.addSubview(progress)
I would like to simulate pressing an arrow key on the hardware keyboard attached to an iPad. In a UI test for a macOS target I can do this:
XCUIElement.typeKey(.rightArrow, modifierFlags: [.option, .command])
but this won't compile for a iOS target supporting iPhone and iPad. Is there an alternative?
What I would like to achieve in the end is moving the text cursor at the beginning of a particular sentence by pressing Option-Command-Arrow left a certain number of times, but if someone knows a better way, I'd be happy to hear it.
In my UI test I'm trying to force the app's user interface style to be light or dark. On macOS, when the system appearance is light, I can force the app to be dark with this code:
var app = XCUIApplication()
app.launchArguments += ["-AppleInterfaceStyle", "Dark"]
app.launch()
Sadly, this doesn't work with a iOS target, and UIScreen.main.traitCollection.userInterfaceStyle is read-only. Is this not possible?
By following the documentation, in Info.plist I have added UIApplicationSupportsPrintCommand = true, but when tapping the navigation item's title and selecting Print, printContent(_:) is never called. On the other hand, when selecting Move, move(_:) is called as expected. What's the problem?
The issue can be reproduced by using the code below in a newly created Xcode project with the App template.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "asdf"
navigationItem.documentProperties = UIDocumentProperties(url: URL(fileURLWithPath: "/asdf"))
navigationItem.titleMenuProvider = { suggestions in
return UIMenu(children: suggestions)
}
}
override func move(_ sender: Any?) {
print("move")
}
override func printContent(_ sender: Any?) {
print("printContent")
}
}
I have a document-based app which displays a view controller with a navigation bar (i.e. it's inside a navigation controller) which is also the detail view controller of a split view controller. I'm using this sample code to just show a back button in the navigation bar of the document view controller:
class DocumentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
splitViewController!.presentsWithGesture = false
navigationItem.backAction = UIAction(handler: { _ in
})
}
}
In a regular width, this works as expected: only the back button is displayed. In a compact width such as a portrait iPhone, the split view seems to display the navigation bar button to show the master view controller (the one with the icon to the right of the back button, labeled “Root View Controller").
According to the documentation of presentsWithGesture:
When this property is false, the split view controller doesn’t install a gesture recognizer for changing the display mode. The split view controller also doesn’t display a button to change the display mode.
Is this a bug, or an error in the documentation, or am I doing something wrong?
According to the App Store Connect API documentation we can get the Default App Clip Experience for an App Store Version, and since on the App Store Connect website we have a single App Clip section for an iOS App, it seems that an App Store Version can have 0 or 1 Default App Clip Experience.
But there is no direct way of getting the Advanced App Clip Experiences. The only way I can see is by getting the App Clip object first for the App, then listing all Default and Advanced App Clip Experiences for that App Clip.
This makes me wonder: are Advanced App Clip Experiences not directly linkes to an App Store Version like the Default App Clip Experience? Does the list of Default App Clip Experiences returned from an App Clip object always contain a single object, or can it be more than one (perhaps older versions linked to old App Store Versions)? What is the relationship between App Store Version, App Clip Default Experiences and App Clip Advanced Experiences?
When using NSTextLayoutManager.addRenderingAttribute(.backgroundColor, value: NSColor.red, for: range), the background color for a line is only drawn as far as the last visible character. There is also a thin space between the lines where the background color is not visible.
Whe using NSLayoutManager.addTemporaryAttribute(.backgroundColor, value: NSColor.red, forCharacterRange: range), the background color is drawn also for newline characters and soft line wraps.
I would like to achieve the effect of using NSLayoutManager.addTemporaryAttribute(.backgroundColor, value: NSColor.red, forCharacterRange: range), but since I'm targeting TextKit 2, I have to avoid using NSLayoutManager. Is there a way to achieve this with NSTextLayoutManager or one of the other related classes in TextKit 2?
The API allows to get customer reviews, but I couldn't find a way to get the average rating for each territory. Is this possible?
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect API
Tags:
App Store Connect API
I'm using this code to get the path of an executable from the audit token provided in NEFilterDataProvider.handleNewFlow(_:), forwarded from the Network Extension to the main app via IPC:
private func securePathFromAuditToken(_ auditToken: Data) throws -> String? {
let secFlags = SecCSFlags()
var secCode: SecCode?
var status = SecCodeCopyGuestWithAttributes(nil, [kSecGuestAttributeAudit: auditToken] as CFDictionary, secFlags, &secCode)
guard let secCode = secCode else {
throw SecError(status)
}
var secStaticCode: SecStaticCode?
status = SecCodeCopyStaticCode(secCode, secFlags, &secStaticCode)
guard let secStaticCode = secStaticCode else {
throw SecError(status)
}
var url: CFURL?
status = SecCodeCopyPath(secStaticCode, secFlags, &url)
guard let url = url as URL? else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(status))
}
return nil
}
But it seems that some processes like trustd, rapportd, nsurlsessiond and timed have a non-nil path. For these executables I have to resort to this code, which I have read is not as secure:
private func insecurePathFromAuditToken(_ auditToken: Data) throws -> String? {
if auditToken.count == MemoryLayout<audit_token_t>.size {
let pid = auditToken.withUnsafeBytes { buffer in
audit_token_to_pid(buffer.baseAddress!.assumingMemoryBound(to: audit_token_t.self).pointee)
}
let pathbuf = UnsafeMutablePointer<Int8>.allocate(capacity: Int(PROC_PIDPATHINFO_SIZE))
defer {
pathbuf.deallocate()
}
let ret = proc_pidpath(pid, pathbuf, UInt32(PROC_PIDPATHINFO_SIZE))
if ret <= 0 {
throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno))
}
return String(cString: pathbuf)
}
return nil
}
This seems to happen with both NEFilterFlow.sourceAppAuditToken and sourceProcessAuditToken. Is this expected? Can it really be that some executables shipped with macOS are not signed?