diff --git a/Examples/React Meets SwiftUI/.gitignore b/Examples/React Meets SwiftUI/.gitignore
new file mode 100755
index 0000000..e86fe25
--- /dev/null
+++ b/Examples/React Meets SwiftUI/.gitignore
@@ -0,0 +1,69 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Typescript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# dotenv environment variables file
+.env
+
+# gatsby files
+.cache/
+public
+
+# Mac files
+.DS_Store
+
+# Yarn
+yarn-error.log
+.pnp/
+.pnp.js
+# Yarn Integrity file
+.yarn-integrity
diff --git a/Examples/React Meets SwiftUI/Children.md b/Examples/React Meets SwiftUI/Children.md
new file mode 100755
index 0000000..d0e474b
--- /dev/null
+++ b/Examples/React Meets SwiftUI/Children.md
@@ -0,0 +1,55 @@
+## Children
+
+I'm still trying to really nail this one down, but it seems possible to pass children to child views in SwiftUI. This example shows a common `Layout`, `Content` composition pattern which I commonly use in React, and is the key to developing reusable, flexible components.
+
+### React
+
+```jsx
+import React from "react";
+
+function Page() {
+ return (
+
+ This is the page content
+
+ );
+}
+
+function Layout({ children }) {
+ return (
+
+ This is the layout
+ {children}
+
+ );
+}
+```
+
+### SwiftUI
+
+The SwiftUI version seems harder to type. Currently, the below example only accepts a `Text` child. Does anyone know how to make this accept any view type?
+
+```swift
+import SwiftUI
+
+struct Page : View {
+ var body: some View {
+ Layout() {
+ Text("This is the page content")
+ }
+ }
+}
+
+struct Layout : View {
+
+ var content: () -> Text
+
+ var body: some View {
+ VStack {
+ Text("This is the layout")
+ content()
+ }
+ }
+}
+
+```
diff --git a/Examples/React Meets SwiftUI/CloneElement.md b/Examples/React Meets SwiftUI/CloneElement.md
new file mode 100755
index 0000000..af7bba0
--- /dev/null
+++ b/Examples/React Meets SwiftUI/CloneElement.md
@@ -0,0 +1,61 @@
+## cloneElement
+
+You'll sometimes use React's `cloneElement` to provide additonal attributes to a child component - i.e, to add an event handler, className, etc. You can achieve similar behaviour in SwiftUI.
+
+### React
+
+```jsx
+import React from "react";
+
+export function PageElement() {
+ return (
+
+
+ This is the page content
+
+
+ );
+}
+
+export function LayoutElement({ children }) {
+ return (
+
+ This is the layout
+ {React.cloneElement(children, {
+ style: {
+ fontWeight: "bold",
+ fontSize: "2rem"
+ }
+ })}
+
+ );
+}
+```
+
+### Swift
+
+```swift
+import SwiftUI
+
+struct PageElement : View {
+ var body: some View {
+ LayoutElement() {
+ Text("This is the page content")
+ }
+ }
+}
+
+struct LayoutElement : View {
+
+ var content: () -> Text
+
+ var body: some View {
+ VStack {
+ Text("This is the layout")
+ content()
+ .bold()
+ .font(.largeTitle)
+ }
+ }
+}
+```
diff --git a/Examples/React Meets SwiftUI/ComponentDidMount.md b/Examples/React Meets SwiftUI/ComponentDidMount.md
new file mode 100755
index 0000000..23d676d
--- /dev/null
+++ b/Examples/React Meets SwiftUI/ComponentDidMount.md
@@ -0,0 +1,125 @@
+## ComponentDidMount
+
+With React it's common to perform one-time operations (such as async fetches to a server) in the `componentDidMount` function or the `useEffect` hook. You can replicate this behaviour using the `onAppear` and `onDisappear` callbacks on any View. This means that you can actually have multiple `onAppear` callbacks attached to multiple views contained within your `body` function. Your parent view can also attach these callbacks to custom child views.
+
+The below example mounts and unmounts the counter readout when it reaches a certain value. We log when the mount/unmount happens.
+
+### React
+
+```jsx
+import React from "react";
+
+export function Counter() {
+ const [count, setCount] = React.useState(0);
+
+ function increment() {
+ setCount(count + 1);
+ }
+
+ return (
+
+ Increment
+ {(count < 10 || count > 12) && }
+
+ );
+}
+
+export function ChildCounter({ count }) {
+ React.useEffect(() => {
+ console.log("mounted");
+
+ return () => {
+ console.log("unmounting");
+ };
+ }, []);
+
+ return {count}
;
+}
+```
+
+### Swift
+
+Note that this only approximates the React behaviour. I'm not sure what the `appear` / `mount` distinction implies, but it seems to provide similar utility.
+
+```swift
+import SwiftUI
+
+struct Counter : View {
+ @State var count = 0
+
+ func increment () {
+ count += 1
+ }
+
+ var body: some View {
+
+ VStack {
+ Button(action: increment) {
+ Text("Increment")
+ }
+ if count < 10 || count > 12 {
+ ChildCounter(count: count)
+ }
+ }
+
+ }
+}
+
+struct ChildCounter : View {
+ var count: Int
+
+ func onMount () {
+ print("on mount")
+ }
+
+ func onUnmount () {
+ print("on unmount")
+ }
+
+ var body: some View {
+ Text("\(count)")
+ .onAppear(perform: onMount)
+ .onDisappear(perform: onUnmount)
+ }
+}
+
+```
+
+You can attach multiple `onAppear` and `onDisappear` callbacks in your `body` function:
+
+```swift
+struct Counter : View {
+ @State var count = 0
+
+ func increment () {
+ count += 1
+ }
+
+ func mount () {
+ print("Child mount")
+ }
+
+ func unmount () {
+ print("Child unmount")
+ }
+
+ func parentMount () {
+ print("parent mount")
+ }
+
+
+ var body: some View {
+ VStack {
+ Button(action: increment) {
+ Text("Increment")
+ }
+ if count < 10 || count > 12 {
+ ChildCounter(count: count)
+ .onAppear(perform: mount)
+ .onDisappear(perform: unmount)
+ }
+ }
+ .onAppear(perform: parentMount)
+ }
+}
+```
diff --git a/Examples/React Meets SwiftUI/Context.md b/Examples/React Meets SwiftUI/Context.md
new file mode 100755
index 0000000..b699938
--- /dev/null
+++ b/Examples/React Meets SwiftUI/Context.md
@@ -0,0 +1,70 @@
+## Context
+
+You can replicate the context functionality found in React by using a combination of `BindableObject`, `Combine` and defining an `environmentObject` for a View. You create a class that adheres to the `BindableObject` and provide that as an argument to `environmentObject` when initiating your parent view. Any child of that parent view can then access the class using `@EnvironmentObject`.
+
+### React
+
+```jsx
+import React, { useContext } from "react";
+
+const Session = React.createContext({ name: "" });
+
+export function ContextProvider() {
+ return (
+
+
+
+ );
+}
+
+export function Parent() {
+ return ;
+}
+
+export function Child() {
+ const session = useContext(Session);
+
+ return Hello {session.name} ;
+}
+```
+
+### SwiftUI
+
+```swift
+import SwiftUI
+import Combine
+
+final class Session: BindableObject {
+ let didChange = PassthroughSubject()
+
+ var name: String {
+ didSet { didChange.send(self) }
+ }
+
+ init(name: String) {
+ self.name = name
+ }
+}
+
+
+struct ContextProvider : View {
+ var body: some View {
+ Parent().environmentObject(Session(name: "Bento"))
+ }
+}
+
+struct Parent : View {
+ var body: some View {
+ Child()
+ }
+}
+
+struct Child : View {
+
+ @EnvironmentObject var session: Session
+
+ var body: some View {
+ Text("Hello \(session.name)")
+ }
+}
+```
diff --git a/Examples/React Meets SwiftUI/README.md b/Examples/React Meets SwiftUI/README.md
new file mode 100755
index 0000000..1e57d59
--- /dev/null
+++ b/Examples/React Meets SwiftUI/README.md
@@ -0,0 +1,13 @@
+# React Meets SwiftUI
+
+I'm looking to learn SwiftUI over the coming weeks and will be using this repository to record various common React design patterns implemented in SwiftUI.
+
+Please note: I'm a total newbie when it comes to Swift, so please contribute where you can to fix my inevitable errors.
+
+### Examples
+
+- [Managing State](State.md)
+- [Using Context](Context.md)
+- [Using Children](Children.md)
+- [Mounting and Unmounting Callbacks](ComponentDidMount.md)
+- [Emulating CloneElement](CloneElement.md)
diff --git a/Examples/React Meets SwiftUI/State.md b/Examples/React Meets SwiftUI/State.md
new file mode 100755
index 0000000..0bb5f1a
--- /dev/null
+++ b/Examples/React Meets SwiftUI/State.md
@@ -0,0 +1,112 @@
+## Managing State
+
+With SwiftUI you can create state in views and pass that state to child views, much as you would in React. You can also pass functions as props which allow child views to control state in parent components.
+
+The example below creates a simple counter. The `ContentView` manages the `count` state, while the child view renders that count and asks the parent to increment.
+
+### React
+
+```jsx
+import React from "react";
+
+export function ContentView() {
+ const [count, setCount] = useState(0);
+
+ function increment() {
+ setCount(count + 1);
+ }
+
+ return (
+
+
Press the button below
+
+
+ );
+}
+
+export function ChildView({ count, increment }) {
+ return (
+
+ );
+}
+```
+
+### SwiftUI
+
+```swift
+import SwiftUI
+
+struct ContentView : View {
+ @State var count = 0
+
+ var body: some View {
+ VStack(spacing: 1.0) {
+ Text("Press the button below")
+ ChildView(
+ counter: count,
+ increment: increment
+ )
+ }
+ }
+
+ func increment() {
+ count += 1
+ }
+}
+
+
+struct ChildView : View {
+ var counter: Int
+ var increment: () -> Void
+
+ var body: some View {
+ VStack {
+ Text("\(counter)")
+ Button(action: increment) {
+ Text("Increment")
+ }
+ }
+ }
+}
+
+```
+
+With SwiftUI you can use `@Binding` to enable child views to alter state provided by parent views. Notice that we prepend the `$` to our count value to pass its binding value. Our child can then alter the `count` state itself without supplying a callback to the parent.
+
+```swift
+import SwiftUI
+
+struct ContentView : View {
+ @State var count = 0
+
+ var body: some View {
+ VStack(spacing: 1.0) {
+ Text("Press the button below")
+ ChildView(
+ counter: $count
+ )
+ }
+ }
+}
+
+
+struct ChildView : View {
+ @Binding var counter: Int
+
+ func increment () {
+ counter += 1
+ }
+
+ var body: some View {
+ VStack {
+ Text("\(counter)")
+ Button(action: increment) {
+ Text("Increment")
+ }
+ }
+ }
+}
+```
diff --git a/Examples/UINote/SwiftUINote.xcodeproj/project.pbxproj b/Examples/UINote/SwiftUINote.xcodeproj/project.pbxproj
new file mode 100755
index 0000000..b166dbd
--- /dev/null
+++ b/Examples/UINote/SwiftUINote.xcodeproj/project.pbxproj
@@ -0,0 +1,508 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 50;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 51197A6922A6B23600E78FC6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A6822A6B23600E78FC6 /* AppDelegate.swift */; };
+ 51197A6B22A6B23600E78FC6 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A6A22A6B23600E78FC6 /* SceneDelegate.swift */; };
+ 51197A6F22A6B23800E78FC6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51197A6E22A6B23800E78FC6 /* Assets.xcassets */; };
+ 51197A7222A6B23800E78FC6 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51197A7122A6B23800E78FC6 /* Preview Assets.xcassets */; };
+ 51197A7522A6B23800E78FC6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51197A7322A6B23800E78FC6 /* LaunchScreen.storyboard */; };
+ 51197A8022A6B23800E78FC6 /* SwiftUINoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A7F22A6B23800E78FC6 /* SwiftUINoteTests.swift */; };
+ 51197A9022A6E01500E78FC6 /* Note.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A8F22A6E01500E78FC6 /* Note.swift */; };
+ 51197A9322A6E1D500E78FC6 /* NoteRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A9222A6E1D500E78FC6 /* NoteRow.swift */; };
+ 51197A9522A7011500E78FC6 /* NoteList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A9422A7011500E78FC6 /* NoteList.swift */; };
+ 51197A9722A70E0400E78FC6 /* NoteData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A9622A70E0400E78FC6 /* NoteData.swift */; };
+ 51197A9922A77E0400E78FC6 /* NoteDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A9822A77E0400E78FC6 /* NoteDetail.swift */; };
+ 51197A9B22A7852C00E78FC6 /* UserData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51197A9A22A7852C00E78FC6 /* UserData.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 51197A7C22A6B23800E78FC6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 51197A5D22A6B23600E78FC6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 51197A6422A6B23600E78FC6;
+ remoteInfo = SwiftUINote;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 51197A6522A6B23600E78FC6 /* SwiftUINote.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUINote.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 51197A6822A6B23600E78FC6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 51197A6A22A6B23600E78FC6 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
+ 51197A6E22A6B23800E78FC6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 51197A7122A6B23800E78FC6 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
+ 51197A7422A6B23800E78FC6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 51197A7622A6B23800E78FC6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 51197A7B22A6B23800E78FC6 /* SwiftUINoteTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftUINoteTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 51197A7F22A6B23800E78FC6 /* SwiftUINoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUINoteTests.swift; sourceTree = ""; };
+ 51197A8122A6B23800E78FC6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 51197A8F22A6E01500E78FC6 /* Note.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Note.swift; sourceTree = ""; };
+ 51197A9222A6E1D500E78FC6 /* NoteRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteRow.swift; sourceTree = ""; };
+ 51197A9422A7011500E78FC6 /* NoteList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteList.swift; sourceTree = ""; };
+ 51197A9622A70E0400E78FC6 /* NoteData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteData.swift; sourceTree = ""; };
+ 51197A9822A77E0400E78FC6 /* NoteDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteDetail.swift; sourceTree = ""; };
+ 51197A9A22A7852C00E78FC6 /* UserData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserData.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 51197A6222A6B23600E78FC6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 51197A7822A6B23800E78FC6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 51197A5C22A6B23600E78FC6 = {
+ isa = PBXGroup;
+ children = (
+ 51197A6722A6B23600E78FC6 /* SwiftUINote */,
+ 51197A7E22A6B23800E78FC6 /* SwiftUINoteTests */,
+ 51197A6622A6B23600E78FC6 /* Products */,
+ );
+ sourceTree = "";
+ };
+ 51197A6622A6B23600E78FC6 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 51197A6522A6B23600E78FC6 /* SwiftUINote.app */,
+ 51197A7B22A6B23800E78FC6 /* SwiftUINoteTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 51197A6722A6B23600E78FC6 /* SwiftUINote */ = {
+ isa = PBXGroup;
+ children = (
+ 51197A8E22A6DFC700E78FC6 /* Models */,
+ 51197A9122A6E1B600E78FC6 /* Views */,
+ 51197A6822A6B23600E78FC6 /* AppDelegate.swift */,
+ 51197A6A22A6B23600E78FC6 /* SceneDelegate.swift */,
+ 51197A6E22A6B23800E78FC6 /* Assets.xcassets */,
+ 51197A7322A6B23800E78FC6 /* LaunchScreen.storyboard */,
+ 51197A7622A6B23800E78FC6 /* Info.plist */,
+ 51197A7022A6B23800E78FC6 /* Preview Content */,
+ );
+ path = SwiftUINote;
+ sourceTree = "";
+ };
+ 51197A7022A6B23800E78FC6 /* Preview Content */ = {
+ isa = PBXGroup;
+ children = (
+ 51197A7122A6B23800E78FC6 /* Preview Assets.xcassets */,
+ );
+ path = "Preview Content";
+ sourceTree = "";
+ };
+ 51197A7E22A6B23800E78FC6 /* SwiftUINoteTests */ = {
+ isa = PBXGroup;
+ children = (
+ 51197A7F22A6B23800E78FC6 /* SwiftUINoteTests.swift */,
+ 51197A8122A6B23800E78FC6 /* Info.plist */,
+ );
+ path = SwiftUINoteTests;
+ sourceTree = "";
+ };
+ 51197A8E22A6DFC700E78FC6 /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ 51197A8F22A6E01500E78FC6 /* Note.swift */,
+ 51197A9622A70E0400E78FC6 /* NoteData.swift */,
+ 51197A9A22A7852C00E78FC6 /* UserData.swift */,
+ );
+ path = Models;
+ sourceTree = "";
+ };
+ 51197A9122A6E1B600E78FC6 /* Views */ = {
+ isa = PBXGroup;
+ children = (
+ 51197A9222A6E1D500E78FC6 /* NoteRow.swift */,
+ 51197A9422A7011500E78FC6 /* NoteList.swift */,
+ 51197A9822A77E0400E78FC6 /* NoteDetail.swift */,
+ );
+ path = Views;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 51197A6422A6B23600E78FC6 /* SwiftUINote */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 51197A8422A6B23800E78FC6 /* Build configuration list for PBXNativeTarget "SwiftUINote" */;
+ buildPhases = (
+ 51197A6122A6B23600E78FC6 /* Sources */,
+ 51197A6222A6B23600E78FC6 /* Frameworks */,
+ 51197A6322A6B23600E78FC6 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftUINote;
+ productName = SwiftUINote;
+ productReference = 51197A6522A6B23600E78FC6 /* SwiftUINote.app */;
+ productType = "com.apple.product-type.application";
+ };
+ 51197A7A22A6B23800E78FC6 /* SwiftUINoteTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 51197A8722A6B23800E78FC6 /* Build configuration list for PBXNativeTarget "SwiftUINoteTests" */;
+ buildPhases = (
+ 51197A7722A6B23800E78FC6 /* Sources */,
+ 51197A7822A6B23800E78FC6 /* Frameworks */,
+ 51197A7922A6B23800E78FC6 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 51197A7D22A6B23800E78FC6 /* PBXTargetDependency */,
+ );
+ name = SwiftUINoteTests;
+ productName = SwiftUINoteTests;
+ productReference = 51197A7B22A6B23800E78FC6 /* SwiftUINoteTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 51197A5D22A6B23600E78FC6 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 1100;
+ LastUpgradeCheck = 1100;
+ ORGANIZATIONNAME = "we'd";
+ TargetAttributes = {
+ 51197A6422A6B23600E78FC6 = {
+ CreatedOnToolsVersion = 11.0;
+ };
+ 51197A7A22A6B23800E78FC6 = {
+ CreatedOnToolsVersion = 11.0;
+ TestTargetID = 51197A6422A6B23600E78FC6;
+ };
+ };
+ };
+ buildConfigurationList = 51197A6022A6B23600E78FC6 /* Build configuration list for PBXProject "SwiftUINote" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 51197A5C22A6B23600E78FC6;
+ productRefGroup = 51197A6622A6B23600E78FC6 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 51197A6422A6B23600E78FC6 /* SwiftUINote */,
+ 51197A7A22A6B23800E78FC6 /* SwiftUINoteTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 51197A6322A6B23600E78FC6 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 51197A7522A6B23800E78FC6 /* LaunchScreen.storyboard in Resources */,
+ 51197A7222A6B23800E78FC6 /* Preview Assets.xcassets in Resources */,
+ 51197A6F22A6B23800E78FC6 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 51197A7922A6B23800E78FC6 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 51197A6122A6B23600E78FC6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 51197A9322A6E1D500E78FC6 /* NoteRow.swift in Sources */,
+ 51197A9722A70E0400E78FC6 /* NoteData.swift in Sources */,
+ 51197A6922A6B23600E78FC6 /* AppDelegate.swift in Sources */,
+ 51197A9B22A7852C00E78FC6 /* UserData.swift in Sources */,
+ 51197A6B22A6B23600E78FC6 /* SceneDelegate.swift in Sources */,
+ 51197A9922A77E0400E78FC6 /* NoteDetail.swift in Sources */,
+ 51197A9022A6E01500E78FC6 /* Note.swift in Sources */,
+ 51197A9522A7011500E78FC6 /* NoteList.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 51197A7722A6B23800E78FC6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 51197A8022A6B23800E78FC6 /* SwiftUINoteTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 51197A7D22A6B23800E78FC6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 51197A6422A6B23600E78FC6 /* SwiftUINote */;
+ targetProxy = 51197A7C22A6B23800E78FC6 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 51197A7322A6B23800E78FC6 /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 51197A7422A6B23800E78FC6 /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 51197A8222A6B23800E78FC6 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 51197A8322A6B23800E78FC6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 51197A8522A6B23800E78FC6 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_ASSET_PATHS = "SwiftUINote/Preview\\ Content";
+ ENABLE_PREVIEWS = YES;
+ INFOPLIST_FILE = SwiftUINote/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.github.agiletalk.SwiftUINote;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 51197A8622A6B23800E78FC6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_ASSET_PATHS = "SwiftUINote/Preview\\ Content";
+ ENABLE_PREVIEWS = YES;
+ INFOPLIST_FILE = SwiftUINote/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.github.agiletalk.SwiftUINote;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ 51197A8822A6B23800E78FC6 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ INFOPLIST_FILE = SwiftUINoteTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.github.agiletalk.SwiftUINoteTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUINote.app/SwiftUINote";
+ };
+ name = Debug;
+ };
+ 51197A8922A6B23800E78FC6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ INFOPLIST_FILE = SwiftUINoteTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = io.github.agiletalk.SwiftUINoteTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftUINote.app/SwiftUINote";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 51197A6022A6B23600E78FC6 /* Build configuration list for PBXProject "SwiftUINote" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 51197A8222A6B23800E78FC6 /* Debug */,
+ 51197A8322A6B23800E78FC6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 51197A8422A6B23800E78FC6 /* Build configuration list for PBXNativeTarget "SwiftUINote" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 51197A8522A6B23800E78FC6 /* Debug */,
+ 51197A8622A6B23800E78FC6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 51197A8722A6B23800E78FC6 /* Build configuration list for PBXNativeTarget "SwiftUINoteTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 51197A8822A6B23800E78FC6 /* Debug */,
+ 51197A8922A6B23800E78FC6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 51197A5D22A6B23600E78FC6 /* Project object */;
+}
diff --git a/Examples/UINote/SwiftUINote.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Examples/UINote/SwiftUINote.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100755
index 0000000..d83239a
--- /dev/null
+++ b/Examples/UINote/SwiftUINote.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Examples/UINote/SwiftUINote.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Examples/UINote/SwiftUINote.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100755
index 0000000..18d9810
--- /dev/null
+++ b/Examples/UINote/SwiftUINote.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/Examples/UINote/SwiftUINote/AppDelegate.swift b/Examples/UINote/SwiftUINote/AppDelegate.swift
new file mode 100755
index 0000000..142c1e0
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/AppDelegate.swift
@@ -0,0 +1,42 @@
+//
+// AppDelegate.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 04/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+ // Override point for customization after application launch.
+ return true
+ }
+
+ func applicationWillTerminate(_ application: UIApplication) {
+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+ NoteData.shared.save()
+ }
+
+ // MARK: UISceneSession Lifecycle
+
+ func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
+ // Called when a new scene session is being created.
+ // Use this method to select a configuration to create the new scene with.
+ return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
+ }
+
+ func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
+ // Called when the user discards a scene session.
+ // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
+ // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
+ }
+
+
+}
+
diff --git a/Examples/UINote/SwiftUINote/Assets.xcassets/AppIcon.appiconset/Contents.json b/Examples/UINote/SwiftUINote/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100755
index 0000000..d8db8d6
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,98 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "20x20",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "20x20",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "3x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "20x20",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "20x20",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "76x76",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "83.5x83.5",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "ios-marketing",
+ "size" : "1024x1024",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Examples/UINote/SwiftUINote/Assets.xcassets/Contents.json b/Examples/UINote/SwiftUINote/Assets.xcassets/Contents.json
new file mode 100755
index 0000000..da4a164
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Examples/UINote/SwiftUINote/Assets.xcassets/nomad.imageset/Contents.json b/Examples/UINote/SwiftUINote/Assets.xcassets/nomad.imageset/Contents.json
new file mode 100755
index 0000000..25fe112
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Assets.xcassets/nomad.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "nomad.jpg",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Examples/UINote/SwiftUINote/Assets.xcassets/nomad.imageset/nomad.jpg b/Examples/UINote/SwiftUINote/Assets.xcassets/nomad.imageset/nomad.jpg
new file mode 100755
index 0000000..6606b32
Binary files /dev/null and b/Examples/UINote/SwiftUINote/Assets.xcassets/nomad.imageset/nomad.jpg differ
diff --git a/Examples/UINote/SwiftUINote/Base.lproj/LaunchScreen.storyboard b/Examples/UINote/SwiftUINote/Base.lproj/LaunchScreen.storyboard
new file mode 100755
index 0000000..865e932
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Examples/UINote/SwiftUINote/Info.plist b/Examples/UINote/SwiftUINote/Info.plist
new file mode 100755
index 0000000..e8bb4c6
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Info.plist
@@ -0,0 +1,62 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+ UIWindowSceneSessionRoleApplication
+
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UISceneConfigurationName
+ Default Configuration
+ UISceneDelegateClassName
+ $(PRODUCT_MODULE_NAME).SceneDelegate
+
+
+
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/Examples/UINote/SwiftUINote/Models/Note.swift b/Examples/UINote/SwiftUINote/Models/Note.swift
new file mode 100755
index 0000000..fc22147
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Models/Note.swift
@@ -0,0 +1,15 @@
+//
+// Note.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 05/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import SwiftUI
+
+struct Note: Hashable, Codable, Identifiable {
+ let id = UUID()
+ var text: String
+ var date = Date()
+}
diff --git a/Examples/UINote/SwiftUINote/Models/NoteData.swift b/Examples/UINote/SwiftUINote/Models/NoteData.swift
new file mode 100755
index 0000000..d5eec13
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Models/NoteData.swift
@@ -0,0 +1,38 @@
+//
+// NoteData.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 05/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import SwiftUI
+
+class NoteData {
+
+ static let shared = NoteData()
+
+ var notes: [Note] = [
+ Note(text: "New Note"),
+ Note(text: "Another Note")
+ ]
+
+ private init() { load() }
+
+ static func dateToString(date: Date) -> String {
+ let formatter = DateFormatter()
+ formatter.dateStyle = .medium
+ return formatter.string(from: date)
+ }
+
+ func save() {
+ UserDefaults.standard.set(try? PropertyListEncoder().encode(notes), forKey: "notes")
+ debugPrint("save called")
+ }
+
+ func load() {
+ if let data = UserDefaults.standard.object(forKey: "notes") as? Data {
+ self.notes = try! PropertyListDecoder().decode([Note].self, from: data)
+ }
+ }
+}
diff --git a/Examples/UINote/SwiftUINote/Models/UserData.swift b/Examples/UINote/SwiftUINote/Models/UserData.swift
new file mode 100755
index 0000000..e2b09d8
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Models/UserData.swift
@@ -0,0 +1,21 @@
+//
+// UserData.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 05/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import SwiftUI
+import Combine
+
+final class UserData: BindableObject {
+ let didChange = PassthroughSubject()
+
+ var notes = NoteData.shared.notes {
+ didSet {
+ didChange.send(self)
+ NoteData.shared.notes = notes
+ }
+ }
+}
diff --git a/Examples/UINote/SwiftUINote/Preview Content/Preview Assets.xcassets/Contents.json b/Examples/UINote/SwiftUINote/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100755
index 0000000..da4a164
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Examples/UINote/SwiftUINote/SceneDelegate.swift b/Examples/UINote/SwiftUINote/SceneDelegate.swift
new file mode 100755
index 0000000..93adb9e
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/SceneDelegate.swift
@@ -0,0 +1,60 @@
+//
+// SceneDelegate.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 04/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import UIKit
+import SwiftUI
+
+class SceneDelegate: UIResponder, UIWindowSceneDelegate {
+
+ var window: UIWindow?
+
+
+ func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
+ // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
+ // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
+ // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
+
+ // Use a UIHostingController as window root view controller
+ let window = UIWindow(frame: UIScreen.main.bounds)
+ window.rootViewController = UIHostingController(rootView: NoteList()
+ .environmentObject(UserData()))
+ self.window = window
+ window.makeKeyAndVisible()
+ }
+
+ func sceneDidDisconnect(_ scene: UIScene) {
+ // Called as the scene is being released by the system.
+ // This occurs shortly after the scene enters the background, or when its session is discarded.
+ // Release any resources associated with this scene that can be re-created the next time the scene connects.
+ // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
+ }
+
+ func sceneDidBecomeActive(_ scene: UIScene) {
+ // Called when the scene has moved from an inactive state to an active state.
+ // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
+ }
+
+ func sceneWillResignActive(_ scene: UIScene) {
+ // Called when the scene will move from an active state to an inactive state.
+ // This may occur due to temporary interruptions (ex. an incoming phone call).
+ }
+
+ func sceneWillEnterForeground(_ scene: UIScene) {
+ // Called as the scene transitions from the background to the foreground.
+ // Use this method to undo the changes made on entering the background.
+ }
+
+ func sceneDidEnterBackground(_ scene: UIScene) {
+ // Called as the scene transitions from the foreground to the background.
+ // Use this method to save data, release shared resources, and store enough scene-specific state information
+ // to restore the scene back to its current state.
+ }
+
+
+}
+
diff --git a/Examples/UINote/SwiftUINote/Views/NoteDetail.swift b/Examples/UINote/SwiftUINote/Views/NoteDetail.swift
new file mode 100755
index 0000000..4f6c3fd
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Views/NoteDetail.swift
@@ -0,0 +1,50 @@
+//
+// NoteDetail.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 05/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import SwiftUI
+
+struct NoteDetail : View {
+ @EnvironmentObject var userData: UserData
+ var note: Note
+ private var text: State
+
+ init(note: Note) {
+ self.note = note
+ self.text = .init(initialValue: note.text)
+ }
+
+ var noteIndex: Int {
+ userData.notes.firstIndex(where: { $0.id == note.id })!
+ }
+
+ var body: some View {
+ VStack {
+ TextField(self.text.binding,
+ placeholder: nil,
+ onEditingChanged: { _ in self.updateNote()},
+ onCommit: {})
+ Spacer()
+ }
+ .padding()
+ .navigationBarTitle(
+ Text(NoteData.dateToString(date: note.date)), displayMode: .inline)
+ }
+
+ private func updateNote() {
+ self.userData.notes[noteIndex].text = self.text.value
+ }
+}
+
+#if DEBUG
+struct NoteDetail_Previews : PreviewProvider {
+ static var previews: some View {
+ NoteDetail(note: NoteData.shared.notes[0])
+ .environmentObject(UserData())
+ }
+}
+#endif
diff --git a/Examples/UINote/SwiftUINote/Views/NoteList.swift b/Examples/UINote/SwiftUINote/Views/NoteList.swift
new file mode 100755
index 0000000..84a3605
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Views/NoteList.swift
@@ -0,0 +1,43 @@
+//
+// NoteList.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 05/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import SwiftUI
+
+struct NoteList : View {
+ @EnvironmentObject var userData: UserData
+
+ var body: some View {
+ NavigationView {
+ List(userData.notes) { note in
+ NavigationButton(destination: NoteDetail(note: note)) {
+ NoteRow(note: note)
+ }
+ }
+ .navigationBarTitle(Text("Notes"), displayMode: .large)
+ .navigationBarItems(trailing: Button(action: self.createNote, label: { Text("New") }))
+ }
+ }
+
+ private func createNote() {
+ let newNote = Note(text: "")
+ self.userData.notes.insert(newNote, at: 0)
+ }
+}
+
+#if DEBUG
+struct NoteList_Previews : PreviewProvider {
+ static var previews: some View {
+ ForEach(["iPhone SE", "iPhone XS Max"].identified(by: \.self)) { deviceName in
+ NoteList()
+ .environmentObject(UserData())
+ .previewDevice(PreviewDevice(rawValue: deviceName))
+ .previewDisplayName(deviceName)
+ }
+ }
+}
+#endif
diff --git a/Examples/UINote/SwiftUINote/Views/NoteRow.swift b/Examples/UINote/SwiftUINote/Views/NoteRow.swift
new file mode 100755
index 0000000..8cbf791
--- /dev/null
+++ b/Examples/UINote/SwiftUINote/Views/NoteRow.swift
@@ -0,0 +1,31 @@
+//
+// NoteRow.swift
+// SwiftUINote
+//
+// Created by chanju Jeon on 05/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import SwiftUI
+
+struct NoteRow : View {
+ var note: Note
+
+ var body: some View {
+ HStack {
+ Text(note.text)
+ }
+ }
+}
+
+#if DEBUG
+struct NoteRow_Previews : PreviewProvider {
+ static var previews: some View {
+ Group {
+ NoteRow(note: Note(text: "New Note"))
+ NoteRow(note: Note(text: "Another Note"))
+ }
+ .previewLayout(.fixed(width: 300, height: 50))
+ }
+}
+#endif
diff --git a/Examples/UINote/SwiftUINoteTests/Info.plist b/Examples/UINote/SwiftUINoteTests/Info.plist
new file mode 100755
index 0000000..64d65ca
--- /dev/null
+++ b/Examples/UINote/SwiftUINoteTests/Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+
+
diff --git a/Examples/UINote/SwiftUINoteTests/SwiftUINoteTests.swift b/Examples/UINote/SwiftUINoteTests/SwiftUINoteTests.swift
new file mode 100755
index 0000000..bef1feb
--- /dev/null
+++ b/Examples/UINote/SwiftUINoteTests/SwiftUINoteTests.swift
@@ -0,0 +1,34 @@
+//
+// SwiftUINoteTests.swift
+// SwiftUINoteTests
+//
+// Created by chanju Jeon on 04/06/2019.
+// Copyright © 2019 we'd. All rights reserved.
+//
+
+import XCTest
+@testable import SwiftUINote
+
+class SwiftUINoteTests: XCTestCase {
+
+ override func setUp() {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ }
+
+ func testExample() {
+ // This is an example of a functional test case.
+ // Use XCTAssert and related functions to verify your tests produce the correct results.
+ }
+
+ func testPerformanceExample() {
+ // This is an example of a performance test case.
+ self.measure {
+ // Put the code you want to measure the time of here.
+ }
+ }
+
+}
diff --git a/Examples/Webview/.gitignore b/Examples/Webview/.gitignore
new file mode 100755
index 0000000..d522f94
--- /dev/null
+++ b/Examples/Webview/.gitignore
@@ -0,0 +1,8 @@
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control?
+#
+# Pods/
+
diff --git a/Examples/Webview/LICENSE b/Examples/Webview/LICENSE
new file mode 100755
index 0000000..d066666
--- /dev/null
+++ b/Examples/Webview/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Jholman8
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/Examples/Webview/README.md b/Examples/Webview/README.md
new file mode 100755
index 0000000..d73cbc6
--- /dev/null
+++ b/Examples/Webview/README.md
@@ -0,0 +1,4 @@
+SwiftUIWebview
+==============
+
+Simple UIWebview Example Written in Swift
diff --git a/Examples/Webview/SwiftTest1/AppDelegate.swift b/Examples/Webview/SwiftTest1/AppDelegate.swift
new file mode 100755
index 0000000..f104df4
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/AppDelegate.swift
@@ -0,0 +1,135 @@
+//
+// AppDelegate.swift
+// SwiftTest1
+//
+// Created by Jacob Holman on 6/3/14.
+// Copyright (c) 2014 Jacob Holman. All rights reserved.
+//
+
+import UIKit
+import CoreData
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
+ // Override point for customization after application launch.
+ return true
+ }
+
+ func applicationWillResignActive(application: UIApplication) {
+ // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+ // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+ }
+
+ func applicationDidEnterBackground(application: UIApplication) {
+ // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+ // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+ }
+
+ func applicationWillEnterForeground(application: UIApplication) {
+ // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+ }
+
+ func applicationDidBecomeActive(application: UIApplication) {
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+ }
+
+ func applicationWillTerminate(application: UIApplication) {
+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+ // Saves changes in the application's managed object context before the application terminates.
+ self.saveContext()
+ }
+
+ func saveContext () {
+ var error: NSError? = nil
+ let managedObjectContext = self.managedObjectContext
+ if managedObjectContext != nil {
+ if managedObjectContext.hasChanges && !managedObjectContext.save(&error) {
+ // Replace this implementation with code to handle the error appropriately.
+ // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
+ //println("Unresolved error \(error), \(error.userInfo)")
+ abort()
+ }
+ }
+ }
+
+ // #pragma mark - Core Data stack
+
+ // Returns the managed object context for the application.
+ // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
+ var managedObjectContext: NSManagedObjectContext {
+ if !_managedObjectContext {
+ let coordinator = self.persistentStoreCoordinator
+ if coordinator != nil {
+ _managedObjectContext = NSManagedObjectContext()
+ _managedObjectContext!.persistentStoreCoordinator = coordinator
+ }
+ }
+ return _managedObjectContext!
+ }
+ var _managedObjectContext: NSManagedObjectContext? = nil
+
+ // Returns the managed object model for the application.
+ // If the model doesn't already exist, it is created from the application's model.
+ var managedObjectModel: NSManagedObjectModel {
+ if !_managedObjectModel {
+ let modelURL = NSBundle.mainBundle().URLForResource("SwiftTest1", withExtension: "momd")
+ _managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
+ }
+ return _managedObjectModel!
+ }
+ var _managedObjectModel: NSManagedObjectModel? = nil
+
+ // Returns the persistent store coordinator for the application.
+ // If the coordinator doesn't already exist, it is created and the application's store added to it.
+ var persistentStoreCoordinator: NSPersistentStoreCoordinator {
+ if !_persistentStoreCoordinator {
+ let storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SwiftTest1.sqlite")
+ var error: NSError? = nil
+ _persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
+ if _persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error) == nil {
+ /*
+ Replace this implementation with code to handle the error appropriately.
+
+ abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
+
+ Typical reasons for an error here include:
+ * The persistent store is not accessible;
+ * The schema for the persistent store is incompatible with current managed object model.
+ Check the error message to determine what the actual problem was.
+
+
+ If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
+
+ If you encounter schema incompatibility errors during development, you can reduce their frequency by:
+ * Simply deleting the existing store:
+ NSFileManager.defaultManager().removeItemAtURL(storeURL, error: nil)
+
+ * Performing automatic lightweight migration by passing the following dictionary as the options parameter:
+ [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true}
+
+ Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
+
+ */
+ //println("Unresolved error \(error), \(error.userInfo)")
+ abort()
+ }
+ }
+ return _persistentStoreCoordinator!
+ }
+ var _persistentStoreCoordinator: NSPersistentStoreCoordinator? = nil
+
+ // #pragma mark - Application's Documents directory
+
+ // Returns the URL to the application's Documents directory.
+ var applicationDocumentsDirectory: NSURL {
+ let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
+ return urls[urls.endIndex-1] as NSURL
+ }
+
+}
+
diff --git a/Examples/Webview/SwiftTest1/Base.lproj/Main.storyboard b/Examples/Webview/SwiftTest1/Base.lproj/Main.storyboard
new file mode 100755
index 0000000..81e7cb1
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/Base.lproj/Main.storyboard
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Examples/Webview/SwiftTest1/Images.xcassets/AppIcon.appiconset/Contents.json b/Examples/Webview/SwiftTest1/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100755
index 0000000..a396706
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "29x29",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "40x40",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "60x60",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Examples/Webview/SwiftTest1/Images.xcassets/LaunchImage.launchimage/Contents.json b/Examples/Webview/SwiftTest1/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100755
index 0000000..c79ebd3
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ },
+ {
+ "orientation" : "portrait",
+ "idiom" : "iphone",
+ "subtype" : "retina4",
+ "extent" : "full-screen",
+ "minimum-system-version" : "7.0",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Examples/Webview/SwiftTest1/Info.plist b/Examples/Webview/SwiftTest1/Info.plist
new file mode 100755
index 0000000..47599d0
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/Info.plist
@@ -0,0 +1,32 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIdentifier
+ byui.${PRODUCT_NAME:rfc1034identifier}
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ ${PRODUCT_NAME}
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+
+
diff --git a/Examples/Webview/SwiftTest1/SwiftTest1.xcdatamodeld/.xccurrentversion b/Examples/Webview/SwiftTest1/SwiftTest1.xcdatamodeld/.xccurrentversion
new file mode 100755
index 0000000..573ca47
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/SwiftTest1.xcdatamodeld/.xccurrentversion
@@ -0,0 +1,8 @@
+
+
+
+
+ _XCCurrentVersionName
+ SwiftTest1.xcdatamodel
+
+
diff --git a/Examples/Webview/SwiftTest1/SwiftTest1.xcdatamodeld/SwiftTest1.xcdatamodel/contents b/Examples/Webview/SwiftTest1/SwiftTest1.xcdatamodeld/SwiftTest1.xcdatamodel/contents
new file mode 100755
index 0000000..193f33c
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/SwiftTest1.xcdatamodeld/SwiftTest1.xcdatamodel/contents
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Examples/Webview/SwiftTest1/ViewController.swift b/Examples/Webview/SwiftTest1/ViewController.swift
new file mode 100755
index 0000000..344b5cc
--- /dev/null
+++ b/Examples/Webview/SwiftTest1/ViewController.swift
@@ -0,0 +1,32 @@
+//
+// ViewController.swift
+// SwiftTest1
+//
+// Created by Jacob Holman on 6/3/14.
+// Copyright (c) 2014 Jacob Holman. All rights reserved.
+//
+
+import UIKit
+
+class ViewController: UIViewController {
+ @IBOutlet var helloWeb : UIWebView
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ }
+
+ @IBAction func buttonTapped(AnyObject) {
+
+ helloWeb.loadRequest(NSURLRequest(URL:NSURL(string:"https://www.google.com")))
+
+ }
+
+ override func didReceiveMemoryWarning() {
+ super.didReceiveMemoryWarning()
+ // Dispose of any resources that can be recreated.
+ }
+
+
+}
+
diff --git a/Examples/Webview/SwiftTest1Tests/Info.plist b/Examples/Webview/SwiftTest1Tests/Info.plist
new file mode 100755
index 0000000..444dfab
--- /dev/null
+++ b/Examples/Webview/SwiftTest1Tests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIdentifier
+ byui.${PRODUCT_NAME:rfc1034identifier}
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ ${PRODUCT_NAME}
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/Examples/Webview/SwiftTest1Tests/SwiftTest1Tests.swift b/Examples/Webview/SwiftTest1Tests/SwiftTest1Tests.swift
new file mode 100755
index 0000000..1b0b118
--- /dev/null
+++ b/Examples/Webview/SwiftTest1Tests/SwiftTest1Tests.swift
@@ -0,0 +1,35 @@
+//
+// SwiftTest1Tests.swift
+// SwiftTest1Tests
+//
+// Created by Jacob Holman on 6/3/14.
+// Copyright (c) 2014 Jacob Holman. All rights reserved.
+//
+
+import XCTest
+
+class SwiftTest1Tests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testExample() {
+ // This is an example of a functional test case.
+ XCTAssert(true, "Pass")
+ }
+
+ func testPerformanceExample() {
+ // This is an example of a performance test case.
+ self.measureBlock() {
+ // Put the code you want to measure the time of here.
+ }
+ }
+
+}
diff --git a/README.md b/README.md
index 5228d9b..a97e67e 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@ Interested in UI and animations in `UIKit`? See project [awesome-ios-ui](https:/
## Navigate
+- [SFSymbols](#sfsymbols)
- [Calculator](#calculator)
- [Creating And Combining Views](#creating-and-combining-views)
- [Building Lists And Navigation](#building-lists-and-navigation)
@@ -34,9 +35,16 @@ Also include:
- InstaFake
- TempusRomanumII
- SwiftUI + Redux
+- React Meets SwiftUI
+- Webview
+- UINote
## Projects
+#### SFSymbols
+
+
+
#### Calculator
diff --git a/Resources/SFSymbols.gif b/Resources/SFSymbols.gif
new file mode 100644
index 0000000..9606053
Binary files /dev/null and b/Resources/SFSymbols.gif differ