What's new in Foundation

RSS for tag

Discuss the WWDC21 session What's new in Foundation.

View Session

Posts under wwdc21-10109 tag

12 Posts
Sort by:
Post not yet marked as solved
2 Replies
309 Views
I was experimenting in a playground with the specifying the kind of measurement with MeasurementUnit and then formatting it with the new foundation formatters, specifically MeasurementFormatter. The particular example I was using is a UnitDuration, exploring the various options and outputs. let times = [1,10,100,1000,10103,2354,83674,182549].map { Measurement<UnitDuration>(value: $0, unit: .microseconds) } print("unitStyle: .medium, unitOptions: .providedUnit") f.unitOptions = .providedUnit f.unitStyle = .medium for t in times {     print(f.string(from: t)) } What I gathered from this exploration is that the unit you use when you create a Measurement<UnitDuration> is stashed within it - in this case I created them with microseconds. What I'd like to do have a uniform scale for the times I'm printing that more aligned with the size based on the values. For example, if all my examples are recorded in microseconds, but more usefully represent milliseconds - is there a way to deal with this just in the formatting itself? I tried updating the unit representation to transform the MeasurementUnit<Duration> instances, but the unit property is a constant: Cannot assign to property: 'unit' is a 'let' constant. I did find the convert(to:) that would let me transform to another specific unit. Is there, by chance, any way to pass in the unit to use directly to a MeasurementFormatter instance, or do I need to back out and transform the various instances to get to a specific unit? Likewise, are there any built-in methods to MeasurementUnit that align the SI units chosen to the scale of the data being used as a value? Or is that something I'd need to create a heuristic/algorithm to and do and apply it myself when I wanted that result?
Posted
by
Post not yet marked as solved
6 Replies
1k Views
Using the new date formatting API available in iOS 15, I would like to respect the 12 vs 24 hour setting on a user-by-user basis. With DateFormatter it can be done as follows, for example, to force a 24 hour time irrespective of the user locale. let formatter = DateFormatter() formatter.dateFormat = "HH:mm" // or hh:mm for 12 h However, I cannot figure out how to force the new date formatting API in iOS 15 to do the same thing, i.e. force displaying 12 vs 24 h. I'm using a format style like this: var formatStyle = dateTime formatStyle.calendar = calendar if let timeZone = timeZone { formatStyle.timeZone = timeZone } return formatStyle And applying it like this, for example, for a given Date instance: date.formatted(formatStyle.hour(.defaultDigits(amPM: .abbreviated))) However, this seems to always give a formatted string relevant to the locale, for example, it's always 12h for the US and always 24h for the UK. This is not the behaviour I really need though, and I'd like to allow each individual user to control what they see irrespective of the locale setting. (Note that there is an in-app setting that allows the user to toggle between the 12 and 24 hour preference, which is the value I'd like to use to set the preference.)
Posted
by
Post marked as solved
4 Replies
602 Views
I would like to update some code that uses DateFormatter, for example, code like this: let date = Date() let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .short formatter.timeZone = TimeZone(identifier: "Europe/London") formatter.string(from: date) With the new date formatting API available in iOS 15, date formatting can be achieved by calling the formatted() method on the date directly, without explicitly requiring a DateFormatter instance, for example: date.formatted(.dateTime.year().month().day().hour().minute()) However, using this new API, I cannot find any way to set the time zone, i.e., the equivalent of the line formatter.timeZone = TimeZone(identifier: "Europe/London"). I'm aware that time zone can be used to format the output, for example date.formatted(.dateTime.timeZone()), but this does not allow one to actually set the time zone. Does anyone know if it is possible?
Posted
by
Post marked as solved
3 Replies
384 Views
I was playing around a bit with the new AttributedString and a few questions came up. I saw this other forum question "JSON encoding of AttributedString with custom attributes", but I did not completely understand the answer and how I would need to use it. I created my custom attribute where I just want to store additional text like this: enum AdditionalTextAttribute: CodableAttributedStringKey, MarkdownDecodableAttributedStringKey {     typealias Value = AttributedString     static let name = "additionalText" } I then extended the AttributeScopes like this: extension AttributeScopes {     struct MyAppAttributes: AttributeScope {         let additionalText: AdditionalTextAttribute         let swiftUI: SwiftUIAttributes     }     var myApp: MyAppAttributes.Type { MyAppAttributes.self } } and I also implemented the AttributeDynamicLookup like this: extension AttributeDynamicLookup {     subscript&lt;T: AttributedStringKey&gt;(dynamicMember keyPath: KeyPath&lt;AttributeScopes.MyAppAttributes, T&gt;) -&gt; T { self[T.self] } } So next I created my AttributedString and added some attributes to it: var attStr = AttributedString("Hello, here is some text.") let range1 = attStr.range(of: "Hello")! let range2 = attStr.range(of: "text")! attStr[range1].additionalText = AttributedString("Hi") attStr[range2].foregroundColor = .blue attStr[range2].font = .caption2 Next I tried to create some JSON from my string and took a look at it like this: let jsonData = try JSONEncoder().encode(attStr) print(String(data: jsonData, encoding: .utf8) ?? "no data") //print result: ["Hello",{},", here is some ",{},"text",{"SwiftUI.ForegroundColor":{},"SwiftUI.Font":{}},".",{}] I guess it makes sense, that both SwiftUI.ForegroundColor and SwiftUI.Font are empty, because they both do not conform to Codable protocol. My first question would be: Why does my additionalText attribute not show up here? I next tried to extend Color to make it codable like this: extension Color: Codable {     enum CodingKeys: CodingKey {         case red, green, blue, alpha         case desc     }     public func encode(to encoder: Encoder) throws {         var container = encoder.container(keyedBy: CodingKeys.self)         guard let cgColor = self.cgColor,               let components = cgColor.components else {                   if description.isEmpty { throw CodingErrors.encoding }                   try container.encode(description, forKey: .desc)                   return               }         try container.encode(components[0], forKey: .red)         try container.encode(components[1], forKey: .green)         try container.encode(components[2], forKey: .blue)         try container.encode(components[3], forKey: .alpha)     }     public init(from decoder: Decoder) throws {         let container = try decoder.container(keyedBy: CodingKeys.self)         if let description = try container.decodeIfPresent(String.self, forKey: .desc) {             if description == "blue" {                 self = Color.blue                 return             }             throw CodingErrors.decoding         }         let red = try container.decode(CGFloat.self, forKey: .red)         let green = try container.decode(CGFloat.self, forKey: .green)         let blue = try container.decode(CGFloat.self, forKey: .blue)         let alpha = try container.decode(CGFloat.self, forKey: .alpha)         self.init(CGColor(red: red, green: green, blue: blue, alpha: alpha))     } } But it looks like even though Color is now codable, the encoding function does not get called when I try to put my attributed string into the JSONEncoder. So my next question is: Does it just not work? Or do I also miss something here? Coming to my last question: If JSONEncoder does not work, how would I store an AttributedString to disk?
Posted
by
Post not yet marked as solved
1 Replies
414 Views
In the "What's new in Foundation" and "What's new in SwiftUI" talks there were examples of creating custom Attributed String styles. The example shown was for a rainbow style. They showed creating the style, serializing the style, using the style in a String - but did not show how to actually render the text in the rainbow style. How is that part done in SwiftUI. ie if I have Text("My fake example of ^[a custom style](customStyle: redAndEmphasized).") How would i create the piece that renders "a custom style" with foregroundColor red and a heavy font? Thanks, Daniel
Posted
by
Post not yet marked as solved
1 Replies
323 Views
I would like to replace my use of DateFormatter with the new date.formatted(_) API but am having some difficulty. For the context of the app in question, it is desirable to use twenty-four hour time regardless of what the user's personal settings are. I have code to do this below: let dateFormatter = DateFormatter() dateFormatter.timeZone = TimeZone.autoupdatingCurrent dateFormatter.dateStyle = .short dateFormatter.timeStyle = .none dateFormatter.dateFormat = "\(dateFormatter.dateFormat!) HH:mm:ss" return dateFormatter.string(from: date) Is there a way to do this using the new API or do I need to continue using the old way?
Posted
by
Post marked as solved
1 Replies
653 Views
I have implemented custom attributes for an AttributedString and successfully converted to NSAttributedString and used in NSTextView with custom coloring and background, works nicely! What does not work is encoding the AttributedString to JSON. The custom attributes are not coded. I use a plain JSON encode like this: let data = JSONEncoder().encode(object) I assume some option is needed for the encoder to deal with the custom attributes (like when converting to NSAttributedString), but I have not been able to find any documentation on how to do this. Any suggestions?
Posted
by
Post not yet marked as solved
1 Replies
674 Views
I am using a AttributedString for markdown. When I add the attributed text, it previews correctly. However, when tapping on the URL it fails to load. Bug or not? I'll post a feedback if so. class ViewController: UIViewController { let string = """ **Thank you** and please _visit_ our [Website](https://www.website.com). ```for item in items``` ```let item one be something``` ```end``` ~~Strikethrough~~ """ @IBOutlet weak var label: UILabel! override func viewDidLoad() { super.viewDidLoad() if let attributedText = try? NSMutableAttributedString(markdown: string, options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace)) { let range = NSRange(location: 0, length: attributedText.mutableString.length) attributedText.addAttribute(NSAttributedString.Key.font, value: UIFont.preferredFont(forTextStyle: .title3), range: range) label.attributedText = attributedText } } }
Posted
by
Post marked as solved
1 Replies
887 Views
Although Text will render two lines if you pass it a 2 line String, it will render the text of both lines concatenated if you pass it as a markdown string. Same if you create an AttributeText before. Examining the AT highlights the markdown structure (NSPresentationIntent, NSInlinePresentationIntent, NSLink, Header, Paragraph, CodeBlock, etc) but this is "flattened" if you will (NSLink works, multiline CodeBlock work). The problem isn't only present in Text. My use case was CoreText 2: I expected that each AttributeText run would be turned into a text layout fragment but NSTextLayoutManager also flattens my example. As an example, a screenshot of a markdown file in Xcode and the rendering in the simulator. 2 "paragraphs" aka 2 text layout fragments. The same test with the EGG recipes rtf file of the CoreText2 WWDC21 session gives predictable results, one text layout fragment per paragraph. I'm wondering if this is a bug or a "feature" of this markdown first iteration? I tried to access the NSPresentationIntent without much luck to populate CoreText2 myself. Any hint would be REALLY welcomed. thank.
Posted
by
Post marked as solved
1 Replies
643 Views
I assumed this was a beta 1 or 2 bug, but as of beta 4 I'm still seeing this behavior, so perhaps I'm doing something wrong: Text is supposed to render AttributedStrings with Markdown. It appears to render correctly when a direct String literal is passed into the Text, but not when the AttributedString is a variable. Am I doing something super dumb? struct ContentView: View {     var text = AttributedString("**Hello**, `world`! Visit our [website](https://www.capitalone.com).")     var body: some View {         VStack {             Text("**Hello**, `world`! Visit our [website](https://www.capitalone.com).")                 .padding()             Text(text)                 .padding()         }     } }
Posted
by
Post not yet marked as solved
0 Replies
414 Views
Hi, I noticed the CodableWithConfiguration protocol in the section of the talk about AttributedString. I'm not really sure what purpose it serves and how it fits in with the original Codable protocol. As far as I can tell there aren't (as of beta 3) any ways to decode/encode objects conforming to this protocol with JSONDecoder/PropertyListDecoder/TopLevelDecoder. I expected there to be something like JSONDecoder().decode(_:from:configuration:) to match the existing JSONDecoder().decode(_:from:). It looks like only the keyed and un-keyed coding containers (but not single value containers) provide ways to decode/encode such objects. I guess my questions are: What are the use cases for these new protocols? Is the configuration object designed to replace the userInfo dictionary on Decoder/Encoder? If I currently pass required information to decoders/encoders via this userInfo dictionary, should I consider using CodableWithConfiguration to avoid typecasting from Any? Why is support for decoding/encoding these objects so limited compared with the original Codable protocols? Thanks!
Posted
by
Post not yet marked as solved
3 Replies
1.5k Views
What is the best way to customize rendering of Markdown styles, in both UIKit and Swift? For instance, how should I tell it what font to use for normal and Bold text? This is what kept us from using NSAttributedString+HTML for embedded string formatting in the past, and AttributedString+Markdown looks even better for this use case, so I'm hoping the fact that we use a custom font won't be a roadblock. Is calling .replaceAttributes() the expected pattern, and just doing this for each expected attribute in each string?
Posted
by