Getting same issue in Xcode 16 beta too
Post
Replies
Boosts
Views
Activity
Got same problem. Seems Xcode doesn't have the write target destination for vision. Not sure if there is something we can do about it, or if this is something Apple has messed up.
Got same thing. Any ideas?
Can't you just check for the OS using #available? Seems to work for me.
extension UIDevice {
/// True if running on vision pro
var isVisionPro: Bool {
if #available(visionOS 1.0, *) {
return true
} else {
return false
}
}
}
Update: Realized this won't work. Will also be true on any non-vision OS.
No, not yet.
if I recall, this was a bug and Apple fixed it. We did ship this feature with different bundle ids. They do share a group id.
I have developed a workaround. Basically, you can copy each cell, using the first table object found for a given set of table cells. It's ugly, but does seem to work. Including some code below to show how you can do it.
class ViewController: NSViewController {
@IBOutlet var textView: NSTextView!
override func viewDidAppear() {
super.viewDidAppear()
let html =
"""
<html>
<head>
<title>Testing Tables</title>
<style>
td {
border: 1px solid;
padding: 10px;
}
</style>
</head>
<body>
<table>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
<tr>
<td>Cell 3</td>
<td>Cell 4</td>
</tr>
</table>
</body>
</html>
"""
let data = html.data(using: .utf8)!
let string = NSMutableAttributedString(html: data, documentAttributes: nil)!
let wholeRange = NSMakeRange(0, string.length)
var table: NSTextTable?
string.enumerateAttribute(.paragraphStyle, in: wholeRange) { value, range, _ in
guard let paragraphStyle = value as? NSParagraphStyle else { return }
let tableBlocks = paragraphStyle.textBlocks.compactMap { $0 as? NSTextTableBlock }
for block in tableBlocks {
if table == nil { table = block.table } // Keep first table found
let newBlock = block.copy(for: table!)
let newStyle = paragraphStyle.mutableCopy() as! NSMutableParagraphStyle
newStyle.textBlocks = [newBlock]
string.addAttribute(.paragraphStyle, value: newStyle, range: range)
}
if tableBlocks.isEmpty { table = nil }
}
textView.textStorage!.setAttributedString(string)
}
}
extension NSTextTableBlock {
func copy(for table: NSTextTable) -> NSTextTableBlock {
let newBlock = NSTextTableBlock(table: table, startingRow: startingRow,
rowSpan: rowSpan, startingColumn: startingColumn, columnSpan: columnSpan)
newBlock.backgroundColor = backgroundColor
newBlock.verticalAlignment = verticalAlignment
for edge: NSRectEdge in [.minX, .minY, .maxX, .maxY] {
for layer: NSTextBlock.Layer in [.border, .margin, .padding] {
let width = width(for: layer, edge: edge)
let valueType = widthValueType(for: layer, edge: edge)
newBlock.setWidth(width, type: valueType, for: layer, edge: edge)
}
newBlock.setBorderColor(borderColor(for: edge), for: edge)
}
for dimension: NSTextBlock.Dimension in [.height, .maximumHeight, .maximumWidth, .minimumHeight, .minimumWidth, .width] {
let value = value(for: dimension)
let valueType = valueType(for: dimension)
newBlock.setValue(value, type: valueType, for: dimension)
}
return newBlock
}
}
We are seeing this too. What seems to be happening is that the NSTextTableBlock objects representing each cell have different table pointers. In other words, each cell gets put into its own table, leading them to appear under one another.
Interestingly, if you convert this attributed string to RTF, and back again, you get something else. You still get separate tables for each cell you input, but it creates empty cells so that the original cells at least have the correct column index, like this...
Conclusion: the HTML input seems to generate a new table object for each cell, instead of a single table object for all cells.
Submitted this a while back under FB13254682. Have added above FB to that.
Seeing same issue in a AppKit app, so unrelated to SwiftUI. Seems the view is correctly positioned, but there is a sublayer of the control that is completely messed up, filling the entire window. Clicking in the place that the button should be does actually sign you in, but the visuals are completely off. Has to be a bug on Apple's side I would guess.
We are seeing the same thing in an AppKit macOS app that is distributed outside the Mac App Store. We sign with the Developer ID, but it says that Shared with You is not in the provisioning profile.
I saw this a few years ago too, only that was with Sign in with Apple. Apple later confirmed that indeed Sign in with Apple is not supported outside the Mac App Store, and the provisioning portal just strips that entitlement out for non-MAS provisioning profiles.
I am seeing this very same behavior with Shared with You. My conclusion is that Shared with You only works with Mac App Store apps, and that you will be able to get it working by distributing it via TestFlight.
If anyone from Apple can confirm that indeed Shared with You is not supported outside the Mac App Store, it would be appreciated. (This sort of thing should be documented; it would have saved me weeks last time).
Thanks for the response.
I have done as suggested, and the Feedback ID is FB10681825
I wasted too much time on this problem, because I missed one very important step. In case it saves someone else some pain, when you provide your widget with dynamic options, you must do that in a separate Intent target in your app. I had just added the IntentHandler straight to the widget extension target, and couldn't figure out why it wasn't working.
Dumb mistake, but also one that leads to the above behavior.
Spoke too soon, as it turns out. Using layoutManager:shouldBreakLineByWordBeforeCharacterAtIndex: is effective if the trailing text is longer than the remaining space on the line. In this case, it does what I described, and you can choose where to put the line break.
The problem is, if the trailing text is short, and fits on the line after the attachment, the layout manager doesn't even look for a line break. It isn't needed, and so there is no way to intervene.
Think inserting line break characters is the most foolproof approach.
I apologize. You are quite correct that you can use layoutManager:shouldBreakLineByWordBeforeCharacterAtIndex: to get the trailing text to wrap. I just needed to "wrap" my head around what that method was doing.
For anyone wondering, the trick is to keep returning false from the delegate method until it passes in the word just after your attachment, at which point you return true. The layout manager will start with the last word on the line, and work back. By returning false, you are telling it you want to break earlier in the line. When you reach the point you actually want to break, you return true to indicate to make the wrap.
The method can return the wide (text container) width when asked for a position training other characters in the line to push the attachment out to the next line. It can return its natural size in other cases. This indeed works. It was one of the approaches I had tried. The problem is then the trailing text...
In order to push out characters following the attachment, you can use layoutManager:shouldBreakLineByWordBeforeCharacterAtIndex:. I tried this, but it seems unrelated to the problem. This method seems to be about wrapping policy; it doesn't give you a way to actually force a wrap at any given character or word boundary, which is more what I need.
I also experimented with layoutManager(_:, shouldSetLineFragmentRect:, lineFragmentUsedRect:, baselineOffset:, in:, forGlyphRange:), but couldn't get that working either.
I wish there was just a method very similar to the attachment bounding rect one for standard text layout. Then it would be trivial. But I can't find a way to intervene in the text layout to cause it to wrap. I think inserting line breaks (which is what I did up until now) is probably the only way.