This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // First we need to create entities | |
| let authorEntity = NSEntityDescription() | |
| authorEntity.name = "Author" | |
| authorEntity.managedObjectClassName = NSStringFromClass(Author.self) | |
| let publicationEntity = NSEntityDescription() | |
| publicationEntity.name = "Publication" | |
| publicationEntity.managedObjectClassName = NSStringFromClass(Publication.self) | |
| publicationEntity.isAbstract = true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | |
| <model> | |
| <entity name="Article" representedClassName="Article" parentEntity="Publication" syncable="YES" codeGenerationType="class"> | |
| <attribute name="text" optional="YES" attributeType="String"/> | |
| </entity> | |
| <entity name="Author" representedClassName="Author" syncable="YES" codeGenerationType="class"> | |
| <attribute name="fullName" optional="YES" attributeType="String"/> | |
| <relationship name="publications" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Publication" inverseName="author" inverseEntity="Publication"/> | |
| </entity> | |
| <entity name="Publication" representedClassName="Publication" isAbstract="YES" syncable="YES" codeGenerationType="class"> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class ImageLoader : BindableObject { | |
| enum LoadingState : Hashable { | |
| // ... | |
| } | |
| let didChange = PassthroughSubject<ImageLoader, Never>() | |
| private(set) var state: LoadingState = .initial { | |
| didSet { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct URLImage : View { | |
| // ... | |
| var body: some View { | |
| if let image = imageLoader.image { | |
| return image | |
| .onAppear {} | |
| .onDisappear {} | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct URLImage : View { | |
| // ... | |
| @ObjectBinding private var imageLoader: ImageLoader | |
| var body: some View { | |
| if let image = imageLoader.image { | |
| return image | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct URLImage : View { | |
| init(url: URL, placeholder: Image = Image(systemName: "photo")) { | |
| // ... | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| struct ImageListView : View { | |
| let urls = (300..<325).map { "https://picsum.photos/\($0)" }.map { URL(string: $0)! } | |
| var body: some View { | |
| NavigationView { | |
| List(urls.identified(by: \.self)) { url in | |
| NavigationButton(destination: ImageDetailView(url: url)) { | |
| HStack { | |
| URLImage(url: url) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extension UIWindow { | |
| /// Print the app's key window hierarchy. | |
| class func printKeyWindowHierarchy() { | |
| UIApplication.shared.keyWindow?.printHierarchy() | |
| } | |
| /// Prints the window's view hierarchy. | |
| func printHierarchy() { | |
| traverseHierarchy { responder, level in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extension UIWindow { | |
| /// Traverse the window's view hierarchy in the same way as the Debug View Hierarchy tool in Xcode. | |
| /// | |
| /// `traverseHierarchy` uses Depth First Search (DFS) to traverse the view hierarchy starting in the window. This way the method can traverse all sub-hierarchies in a correct order. | |
| /// | |
| /// - parameters: | |
| /// - visitor: The closure executed for every view object in the hierarchy | |
| /// - responder: The view object, `UIView`, `UIViewController`, or `UIWindow` instance. | |
| /// - level: The depth level in the view hierarchy. | |
| func traverseHierarchy(_ visitor: (_ responder: UIResponder, _ level: Int) -> Void) { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extension UIResponder { | |
| /// The responder chain from the target responder (self) | |
| /// to the `UIApplication` and the app delegate | |
| var responderChain: [UIResponder] { | |
| var responderChain: [UIResponder] = [] | |
| var currentResponder: UIResponder? = self | |
| while currentResponder != nil { | |
| responderChain.append(currentResponder!) |