├── .gitignore ├── Notes-Swift ├── Notes-Swift.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Notes-Swift │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── Note.swift │ ├── NoteDetailViewController.swift │ └── NotesListTableViewController.swift └── Notes-SwiftTests │ ├── Info.plist │ └── Notes_SwiftTests.swift ├── README.md └── instructionImages ├── 10Entries.png ├── AppDetails.png ├── AppTemplate.png ├── ApplicationType.png ├── CellIdentifier.png ├── CellIdentifier2.png ├── CodeConnection.png ├── ConstraintsDone.png ├── CreateConstraints.png ├── Delete.png ├── DetailDesign.png ├── EmbedNavigation.png ├── EmpyList.png ├── IBOutlet1.png ├── InitialVC.png ├── Navigation_TableView.png ├── NewFile.png ├── NewSwiftFile.png ├── NotesListTableViewController.png ├── ObjectLibrary.png ├── Scale.png ├── Segue1.png ├── addSegue.png ├── barbutton_item.png ├── nameSegue.png ├── namingOutlet.png ├── realnotes.png ├── textfieldConstraints.png └── textviewConstraints.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | DerivedData 5 | xcuserdata 6 | !default.mode1v3 7 | !default.mode2v3 8 | !default.pbxuser 9 | !default.perspectivev3 10 | *.hmap 11 | *.ipa 12 | *.mode1v3 13 | *.mode2v3 14 | *.moved-aside 15 | *.pbxuser 16 | *.perspective 17 | *.perspectivev3 18 | *.swp 19 | *.xccheckout 20 | *.xcuserstate 21 | *~.nib 22 | .DS_Store -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BC0AFF721A149B8F000BABEA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC0AFF711A149B8F000BABEA /* AppDelegate.swift */; }; 11 | BC0AFF771A149B8F000BABEA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BC0AFF751A149B8F000BABEA /* Main.storyboard */; }; 12 | BC0AFF791A149B8F000BABEA /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BC0AFF781A149B8F000BABEA /* Images.xcassets */; }; 13 | BC0AFF7C1A149B8F000BABEA /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC0AFF7A1A149B8F000BABEA /* LaunchScreen.xib */; }; 14 | BC0AFF881A149B8F000BABEA /* Notes_SwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC0AFF871A149B8F000BABEA /* Notes_SwiftTests.swift */; }; 15 | BC0AFF921A149CE5000BABEA /* NotesListTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC0AFF911A149CE5000BABEA /* NotesListTableViewController.swift */; }; 16 | BC0AFF941A14FAF1000BABEA /* Note.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC0AFF931A14FAF1000BABEA /* Note.swift */; }; 17 | BC0AFF961A14FEF1000BABEA /* NoteDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC0AFF951A14FEF1000BABEA /* NoteDetailViewController.swift */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | BC0AFF821A149B8F000BABEA /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = BC0AFF641A149B8F000BABEA /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = BC0AFF6B1A149B8F000BABEA; 26 | remoteInfo = "Notes-Swift"; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | BC0AFF6C1A149B8F000BABEA /* Notes-Swift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Notes-Swift.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | BC0AFF701A149B8F000BABEA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | BC0AFF711A149B8F000BABEA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 34 | BC0AFF761A149B8F000BABEA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 35 | BC0AFF781A149B8F000BABEA /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 36 | BC0AFF7B1A149B8F000BABEA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 37 | BC0AFF811A149B8F000BABEA /* Notes-SwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Notes-SwiftTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | BC0AFF861A149B8F000BABEA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 39 | BC0AFF871A149B8F000BABEA /* Notes_SwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notes_SwiftTests.swift; sourceTree = ""; }; 40 | BC0AFF911A149CE5000BABEA /* NotesListTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotesListTableViewController.swift; sourceTree = ""; }; 41 | BC0AFF931A14FAF1000BABEA /* Note.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Note.swift; sourceTree = ""; }; 42 | BC0AFF951A14FEF1000BABEA /* NoteDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteDetailViewController.swift; sourceTree = ""; }; 43 | /* End PBXFileReference section */ 44 | 45 | /* Begin PBXFrameworksBuildPhase section */ 46 | BC0AFF691A149B8F000BABEA /* Frameworks */ = { 47 | isa = PBXFrameworksBuildPhase; 48 | buildActionMask = 2147483647; 49 | files = ( 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | BC0AFF7E1A149B8F000BABEA /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | BC0AFF631A149B8F000BABEA = { 64 | isa = PBXGroup; 65 | children = ( 66 | BC0AFF6E1A149B8F000BABEA /* Notes-Swift */, 67 | BC0AFF841A149B8F000BABEA /* Notes-SwiftTests */, 68 | BC0AFF6D1A149B8F000BABEA /* Products */, 69 | ); 70 | sourceTree = ""; 71 | }; 72 | BC0AFF6D1A149B8F000BABEA /* Products */ = { 73 | isa = PBXGroup; 74 | children = ( 75 | BC0AFF6C1A149B8F000BABEA /* Notes-Swift.app */, 76 | BC0AFF811A149B8F000BABEA /* Notes-SwiftTests.xctest */, 77 | ); 78 | name = Products; 79 | sourceTree = ""; 80 | }; 81 | BC0AFF6E1A149B8F000BABEA /* Notes-Swift */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | BC0AFF951A14FEF1000BABEA /* NoteDetailViewController.swift */, 85 | BC0AFF911A149CE5000BABEA /* NotesListTableViewController.swift */, 86 | BC0AFF711A149B8F000BABEA /* AppDelegate.swift */, 87 | BC0AFF751A149B8F000BABEA /* Main.storyboard */, 88 | BC0AFF931A14FAF1000BABEA /* Note.swift */, 89 | BC0AFF781A149B8F000BABEA /* Images.xcassets */, 90 | BC0AFF7A1A149B8F000BABEA /* LaunchScreen.xib */, 91 | BC0AFF6F1A149B8F000BABEA /* Supporting Files */, 92 | ); 93 | path = "Notes-Swift"; 94 | sourceTree = ""; 95 | }; 96 | BC0AFF6F1A149B8F000BABEA /* Supporting Files */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | BC0AFF701A149B8F000BABEA /* Info.plist */, 100 | ); 101 | name = "Supporting Files"; 102 | sourceTree = ""; 103 | }; 104 | BC0AFF841A149B8F000BABEA /* Notes-SwiftTests */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | BC0AFF871A149B8F000BABEA /* Notes_SwiftTests.swift */, 108 | BC0AFF851A149B8F000BABEA /* Supporting Files */, 109 | ); 110 | path = "Notes-SwiftTests"; 111 | sourceTree = ""; 112 | }; 113 | BC0AFF851A149B8F000BABEA /* Supporting Files */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | BC0AFF861A149B8F000BABEA /* Info.plist */, 117 | ); 118 | name = "Supporting Files"; 119 | sourceTree = ""; 120 | }; 121 | /* End PBXGroup section */ 122 | 123 | /* Begin PBXNativeTarget section */ 124 | BC0AFF6B1A149B8F000BABEA /* Notes-Swift */ = { 125 | isa = PBXNativeTarget; 126 | buildConfigurationList = BC0AFF8B1A149B8F000BABEA /* Build configuration list for PBXNativeTarget "Notes-Swift" */; 127 | buildPhases = ( 128 | BC0AFF681A149B8F000BABEA /* Sources */, 129 | BC0AFF691A149B8F000BABEA /* Frameworks */, 130 | BC0AFF6A1A149B8F000BABEA /* Resources */, 131 | ); 132 | buildRules = ( 133 | ); 134 | dependencies = ( 135 | ); 136 | name = "Notes-Swift"; 137 | productName = "Notes-Swift"; 138 | productReference = BC0AFF6C1A149B8F000BABEA /* Notes-Swift.app */; 139 | productType = "com.apple.product-type.application"; 140 | }; 141 | BC0AFF801A149B8F000BABEA /* Notes-SwiftTests */ = { 142 | isa = PBXNativeTarget; 143 | buildConfigurationList = BC0AFF8E1A149B8F000BABEA /* Build configuration list for PBXNativeTarget "Notes-SwiftTests" */; 144 | buildPhases = ( 145 | BC0AFF7D1A149B8F000BABEA /* Sources */, 146 | BC0AFF7E1A149B8F000BABEA /* Frameworks */, 147 | BC0AFF7F1A149B8F000BABEA /* Resources */, 148 | ); 149 | buildRules = ( 150 | ); 151 | dependencies = ( 152 | BC0AFF831A149B8F000BABEA /* PBXTargetDependency */, 153 | ); 154 | name = "Notes-SwiftTests"; 155 | productName = "Notes-SwiftTests"; 156 | productReference = BC0AFF811A149B8F000BABEA /* Notes-SwiftTests.xctest */; 157 | productType = "com.apple.product-type.bundle.unit-test"; 158 | }; 159 | /* End PBXNativeTarget section */ 160 | 161 | /* Begin PBXProject section */ 162 | BC0AFF641A149B8F000BABEA /* Project object */ = { 163 | isa = PBXProject; 164 | attributes = { 165 | LastUpgradeCheck = 0610; 166 | ORGANIZATIONNAME = MakeSchool; 167 | TargetAttributes = { 168 | BC0AFF6B1A149B8F000BABEA = { 169 | CreatedOnToolsVersion = 6.1; 170 | }; 171 | BC0AFF801A149B8F000BABEA = { 172 | CreatedOnToolsVersion = 6.1; 173 | TestTargetID = BC0AFF6B1A149B8F000BABEA; 174 | }; 175 | }; 176 | }; 177 | buildConfigurationList = BC0AFF671A149B8F000BABEA /* Build configuration list for PBXProject "Notes-Swift" */; 178 | compatibilityVersion = "Xcode 3.2"; 179 | developmentRegion = English; 180 | hasScannedForEncodings = 0; 181 | knownRegions = ( 182 | en, 183 | Base, 184 | ); 185 | mainGroup = BC0AFF631A149B8F000BABEA; 186 | productRefGroup = BC0AFF6D1A149B8F000BABEA /* Products */; 187 | projectDirPath = ""; 188 | projectRoot = ""; 189 | targets = ( 190 | BC0AFF6B1A149B8F000BABEA /* Notes-Swift */, 191 | BC0AFF801A149B8F000BABEA /* Notes-SwiftTests */, 192 | ); 193 | }; 194 | /* End PBXProject section */ 195 | 196 | /* Begin PBXResourcesBuildPhase section */ 197 | BC0AFF6A1A149B8F000BABEA /* Resources */ = { 198 | isa = PBXResourcesBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | BC0AFF771A149B8F000BABEA /* Main.storyboard in Resources */, 202 | BC0AFF7C1A149B8F000BABEA /* LaunchScreen.xib in Resources */, 203 | BC0AFF791A149B8F000BABEA /* Images.xcassets in Resources */, 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | }; 207 | BC0AFF7F1A149B8F000BABEA /* Resources */ = { 208 | isa = PBXResourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | /* End PBXResourcesBuildPhase section */ 215 | 216 | /* Begin PBXSourcesBuildPhase section */ 217 | BC0AFF681A149B8F000BABEA /* Sources */ = { 218 | isa = PBXSourcesBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | BC0AFF921A149CE5000BABEA /* NotesListTableViewController.swift in Sources */, 222 | BC0AFF961A14FEF1000BABEA /* NoteDetailViewController.swift in Sources */, 223 | BC0AFF721A149B8F000BABEA /* AppDelegate.swift in Sources */, 224 | BC0AFF941A14FAF1000BABEA /* Note.swift in Sources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | BC0AFF7D1A149B8F000BABEA /* Sources */ = { 229 | isa = PBXSourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | BC0AFF881A149B8F000BABEA /* Notes_SwiftTests.swift in Sources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | /* End PBXSourcesBuildPhase section */ 237 | 238 | /* Begin PBXTargetDependency section */ 239 | BC0AFF831A149B8F000BABEA /* PBXTargetDependency */ = { 240 | isa = PBXTargetDependency; 241 | target = BC0AFF6B1A149B8F000BABEA /* Notes-Swift */; 242 | targetProxy = BC0AFF821A149B8F000BABEA /* PBXContainerItemProxy */; 243 | }; 244 | /* End PBXTargetDependency section */ 245 | 246 | /* Begin PBXVariantGroup section */ 247 | BC0AFF751A149B8F000BABEA /* Main.storyboard */ = { 248 | isa = PBXVariantGroup; 249 | children = ( 250 | BC0AFF761A149B8F000BABEA /* Base */, 251 | ); 252 | name = Main.storyboard; 253 | sourceTree = ""; 254 | }; 255 | BC0AFF7A1A149B8F000BABEA /* LaunchScreen.xib */ = { 256 | isa = PBXVariantGroup; 257 | children = ( 258 | BC0AFF7B1A149B8F000BABEA /* Base */, 259 | ); 260 | name = LaunchScreen.xib; 261 | sourceTree = ""; 262 | }; 263 | /* End PBXVariantGroup section */ 264 | 265 | /* Begin XCBuildConfiguration section */ 266 | BC0AFF891A149B8F000BABEA /* Debug */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_SEARCH_USER_PATHS = NO; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BOOL_CONVERSION = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_INT_CONVERSION = YES; 280 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 281 | CLANG_WARN_UNREACHABLE_CODE = YES; 282 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 283 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 284 | COPY_PHASE_STRIP = NO; 285 | ENABLE_STRICT_OBJC_MSGSEND = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu99; 287 | GCC_DYNAMIC_NO_PIC = NO; 288 | GCC_OPTIMIZATION_LEVEL = 0; 289 | GCC_PREPROCESSOR_DEFINITIONS = ( 290 | "DEBUG=1", 291 | "$(inherited)", 292 | ); 293 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 296 | GCC_WARN_UNDECLARED_SELECTOR = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 298 | GCC_WARN_UNUSED_FUNCTION = YES; 299 | GCC_WARN_UNUSED_VARIABLE = YES; 300 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 301 | MTL_ENABLE_DEBUG_INFO = YES; 302 | ONLY_ACTIVE_ARCH = YES; 303 | SDKROOT = iphoneos; 304 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 305 | }; 306 | name = Debug; 307 | }; 308 | BC0AFF8A1A149B8F000BABEA /* Release */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 313 | CLANG_CXX_LIBRARY = "libc++"; 314 | CLANG_ENABLE_MODULES = YES; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_WARN_BOOL_CONVERSION = YES; 317 | CLANG_WARN_CONSTANT_CONVERSION = YES; 318 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 319 | CLANG_WARN_EMPTY_BODY = YES; 320 | CLANG_WARN_ENUM_CONVERSION = YES; 321 | CLANG_WARN_INT_CONVERSION = YES; 322 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 323 | CLANG_WARN_UNREACHABLE_CODE = YES; 324 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 325 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 326 | COPY_PHASE_STRIP = YES; 327 | ENABLE_NS_ASSERTIONS = NO; 328 | ENABLE_STRICT_OBJC_MSGSEND = YES; 329 | GCC_C_LANGUAGE_STANDARD = gnu99; 330 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 331 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 332 | GCC_WARN_UNDECLARED_SELECTOR = YES; 333 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 334 | GCC_WARN_UNUSED_FUNCTION = YES; 335 | GCC_WARN_UNUSED_VARIABLE = YES; 336 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 337 | MTL_ENABLE_DEBUG_INFO = NO; 338 | SDKROOT = iphoneos; 339 | VALIDATE_PRODUCT = YES; 340 | }; 341 | name = Release; 342 | }; 343 | BC0AFF8C1A149B8F000BABEA /* Debug */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 347 | INFOPLIST_FILE = "Notes-Swift/Info.plist"; 348 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 349 | PRODUCT_NAME = "$(TARGET_NAME)"; 350 | }; 351 | name = Debug; 352 | }; 353 | BC0AFF8D1A149B8F000BABEA /* Release */ = { 354 | isa = XCBuildConfiguration; 355 | buildSettings = { 356 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 357 | INFOPLIST_FILE = "Notes-Swift/Info.plist"; 358 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 359 | PRODUCT_NAME = "$(TARGET_NAME)"; 360 | }; 361 | name = Release; 362 | }; 363 | BC0AFF8F1A149B8F000BABEA /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | BUNDLE_LOADER = "$(TEST_HOST)"; 367 | FRAMEWORK_SEARCH_PATHS = ( 368 | "$(SDKROOT)/Developer/Library/Frameworks", 369 | "$(inherited)", 370 | ); 371 | GCC_PREPROCESSOR_DEFINITIONS = ( 372 | "DEBUG=1", 373 | "$(inherited)", 374 | ); 375 | INFOPLIST_FILE = "Notes-SwiftTests/Info.plist"; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Notes-Swift.app/Notes-Swift"; 379 | }; 380 | name = Debug; 381 | }; 382 | BC0AFF901A149B8F000BABEA /* Release */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | BUNDLE_LOADER = "$(TEST_HOST)"; 386 | FRAMEWORK_SEARCH_PATHS = ( 387 | "$(SDKROOT)/Developer/Library/Frameworks", 388 | "$(inherited)", 389 | ); 390 | INFOPLIST_FILE = "Notes-SwiftTests/Info.plist"; 391 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 392 | PRODUCT_NAME = "$(TARGET_NAME)"; 393 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Notes-Swift.app/Notes-Swift"; 394 | }; 395 | name = Release; 396 | }; 397 | /* End XCBuildConfiguration section */ 398 | 399 | /* Begin XCConfigurationList section */ 400 | BC0AFF671A149B8F000BABEA /* Build configuration list for PBXProject "Notes-Swift" */ = { 401 | isa = XCConfigurationList; 402 | buildConfigurations = ( 403 | BC0AFF891A149B8F000BABEA /* Debug */, 404 | BC0AFF8A1A149B8F000BABEA /* Release */, 405 | ); 406 | defaultConfigurationIsVisible = 0; 407 | defaultConfigurationName = Release; 408 | }; 409 | BC0AFF8B1A149B8F000BABEA /* Build configuration list for PBXNativeTarget "Notes-Swift" */ = { 410 | isa = XCConfigurationList; 411 | buildConfigurations = ( 412 | BC0AFF8C1A149B8F000BABEA /* Debug */, 413 | BC0AFF8D1A149B8F000BABEA /* Release */, 414 | ); 415 | defaultConfigurationIsVisible = 0; 416 | defaultConfigurationName = Release; 417 | }; 418 | BC0AFF8E1A149B8F000BABEA /* Build configuration list for PBXNativeTarget "Notes-SwiftTests" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | BC0AFF8F1A149B8F000BABEA /* Debug */, 422 | BC0AFF901A149B8F000BABEA /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | /* End XCConfigurationList section */ 428 | }; 429 | rootObject = BC0AFF641A149B8F000BABEA /* Project object */; 430 | } 431 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Notes-Swift 4 | // 5 | // Created by Dion Larson on 11/12/14. 6 | // Copyright (c) 2014 MakeSchool. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreData 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 19 | // Override point for customization after application launch. 20 | return true 21 | } 22 | 23 | func applicationWillResignActive(application: UIApplication) { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | func applicationDidEnterBackground(application: UIApplication) { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | func applicationWillEnterForeground(application: UIApplication) { 34 | // 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. 35 | } 36 | 37 | func applicationDidBecomeActive(application: UIApplication) { 38 | // 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. 39 | } 40 | 41 | func applicationWillTerminate(application: UIApplication) { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | // Saves changes in the application's managed object context before the application terminates. 44 | self.saveContext() 45 | } 46 | 47 | // MARK: - Core Data stack 48 | 49 | lazy var applicationDocumentsDirectory: NSURL = { 50 | // The directory the application uses to store the Core Data store file. This code uses a directory named "com.makeschool.Notes-Swift" in the application's documents Application Support directory. 51 | let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) 52 | return urls[urls.count-1] as NSURL 53 | }() 54 | 55 | lazy var managedObjectModel: NSManagedObjectModel = { 56 | // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model. 57 | let modelURL = NSBundle.mainBundle().URLForResource("Notes", withExtension: "momd")! 58 | return NSManagedObjectModel(contentsOfURL: modelURL)! 59 | }() 60 | 61 | lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = { 62 | // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail. 63 | // Create the coordinator and store 64 | var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) 65 | let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("Notes.sqlite") 66 | var error: NSError? = nil 67 | var failureReason = "There was an error creating or loading the application's saved data." 68 | if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil { 69 | coordinator = nil 70 | // Report any error we got. 71 | let dict = NSMutableDictionary() 72 | dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" 73 | dict[NSLocalizedFailureReasonErrorKey] = failureReason 74 | dict[NSUnderlyingErrorKey] = error 75 | error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict) 76 | // Replace this with code to handle the error appropriately. 77 | // 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. 78 | NSLog("Unresolved error \(error), \(error!.userInfo)") 79 | abort() 80 | } 81 | 82 | return coordinator 83 | }() 84 | 85 | lazy var managedObjectContext: NSManagedObjectContext? = { 86 | // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail. 87 | let coordinator = self.persistentStoreCoordinator 88 | if coordinator == nil { 89 | return nil 90 | } 91 | var managedObjectContext = NSManagedObjectContext() 92 | managedObjectContext.persistentStoreCoordinator = coordinator 93 | return managedObjectContext 94 | }() 95 | 96 | // MARK: - Core Data Saving support 97 | 98 | func saveContext () { 99 | if let moc = self.managedObjectContext { 100 | var error: NSError? = nil 101 | if moc.hasChanges && !moc.save(&error) { 102 | // Replace this implementation with code to handle the error appropriately. 103 | // 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. 104 | NSLog("Unresolved error \(error), \(error!.userInfo)") 105 | abort() 106 | } 107 | } 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.makeschool.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/Note.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Note.swift 3 | // Notes-Swift 4 | // 5 | // Created by Dion Larson on 11/13/14. 6 | // Copyright (c) 2014 MakeSchool. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Note { 12 | var title = "" 13 | var content = "" 14 | } -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/NoteDetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteDetailViewController.swift 3 | // Notes-Swift 4 | // 5 | // Created by Dion Larson on 11/13/14. 6 | // Copyright (c) 2014 MakeSchool. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NoteDetailViewController: UIViewController { 12 | 13 | 14 | @IBOutlet weak var contentTextField: UITextView! 15 | @IBOutlet weak var titleTextField: UITextField! 16 | 17 | var note: Note! 18 | 19 | override func viewWillAppear(animated: Bool) { 20 | super.viewWillAppear(animated) 21 | 22 | titleTextField.text = note.title 23 | contentTextField.text = note.content 24 | } 25 | 26 | override func viewWillDisappear(animated: Bool) { 27 | super.viewWillDisappear(animated) 28 | 29 | note.title = titleTextField.text 30 | note.content = contentTextField.text 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-Swift/NotesListTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotesListTableViewController.swift 3 | // Notes-Swift 4 | // 5 | // Created by Dion Larson on 11/13/14. 6 | // Copyright (c) 2014 MakeSchool. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NotesListTableViewController: UITableViewController { 12 | 13 | var notes: [Note] = [] 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | // Uncomment the following line to preserve selection between presentations 19 | // self.clearsSelectionOnViewWillAppear = false 20 | 21 | // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 22 | // self.navigationItem.rightBarButtonItem = self.editButtonItem() 23 | } 24 | 25 | override func viewWillAppear(animated: Bool) { 26 | super.viewWillAppear(animated) 27 | 28 | tableView.reloadData() 29 | } 30 | 31 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 32 | if segue.identifier! == "showNote" { 33 | var noteDetailViewController = segue.destinationViewController as NoteDetailViewController 34 | var selectedIndexPath = tableView.indexPathForSelectedRow() 35 | noteDetailViewController.note = notes[selectedIndexPath!.row] 36 | } else if segue.identifier! == "addNote" { 37 | var note = Note() 38 | notes.append(note) 39 | var noteDetailViewController = segue.destinationViewController as NoteDetailViewController 40 | noteDetailViewController.note = note 41 | } 42 | } 43 | 44 | override func didReceiveMemoryWarning() { 45 | super.didReceiveMemoryWarning() 46 | // Dispose of any resources that can be recreated. 47 | } 48 | 49 | // MARK: - Table view data source 50 | 51 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 52 | // Return the number of rows in the section. 53 | return notes.count 54 | } 55 | 56 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 57 | var cell = tableView.dequeueReusableCellWithIdentifier("NotesCell", forIndexPath: indexPath) as UITableViewCell 58 | 59 | cell.textLabel!.text = notes[indexPath.row].title 60 | 61 | return cell 62 | } 63 | 64 | 65 | override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 66 | notes.removeAtIndex(indexPath.row) 67 | tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-SwiftTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.makeschool.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Notes-Swift/Notes-SwiftTests/Notes_SwiftTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notes_SwiftTests.swift 3 | // Notes-SwiftTests 4 | // 5 | // Created by Dion Larson on 11/12/14. 6 | // Copyright (c) 2014 MakeSchool. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class Notes_SwiftTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | There is an Objective-C version of this tutorial located [here](https://github.com/MakeGamesWithUs/iOS8-Notes). This code was last tested on Xcode 6.1.1 (6A2008a). There may be errors in other versions of Xcode. 2 | 3 | #Setting up a new project 4 | 5 | Open Xcode 6.1 (6A1052d) and select *File -> New Project*. Then choose create a *Single View Application*: 6 | 7 | ![image](instructionImages/ApplicationType.png) 8 | 9 | Choose the name for your application and select *Swift* as language: 10 | 11 | ![image](instructionImages/AppDetails.png) 12 | 13 | After hitting *next* and choosing a project location Xcode will create the new project, based on a project template. You will see that the template contains, among additional files, an `AppDelegate` class, a `ViewController` class and a `Main.storyboard` file: 14 | 15 | ![image](instructionImages/AppTemplate.png) 16 | 17 | #Configuring the Storyboard 18 | 19 | We want to create an app that can display notes. The app will consist of two different view controllers, the first one will display a list of notes, the second one will display the details of a note when it is selected from the list. We will design the entire layout of this app in storyboard. Open the `Main.storyboard` file to get started. 20 | 21 | ##Setting up the Notes List View Controller 22 | 23 | Let's start by creating the first view controller that displays a list of notes. Whenever we want to display items in a list on iOS we use a component called `UITableView`. Since that component is used very often Interface Builder provides a template view controller called *Table View Controller* that provides a basic table view and a ViewController that is associated with it. Before we create it let's remove the default view controller that has been created as part of the template: 24 | 25 | - Select the view controller in the Storyboard by clicking into it and hit the delete key 26 | - Remove the `ViewController.swift` class from Xcode (Select "Move to Trash" when prompt appears) 27 | 28 | Now your Xcode project should look like this: 29 | 30 | ![image](instructionImages/Delete.png) 31 | 32 | Now select the *Table View Controller* from the Object Library on the bottom right of the Interface Builder UI. You can use the search bar at the bottom to filter the list: 33 | 34 | ![image](instructionImages/ObjectLibrary.png) 35 | 36 | Drag the selected controller to the storyboard stage. Now you have added the first view controller to your app. 37 | 38 | iOS needs to know which view controller in our app should be displayed first (this view controller is called the root view controller). In Interface Builder we can configure this by selecting the table view controller and opening the Attributes Inspector in the right panel. Check the box for *is initial View Controller*: 39 | 40 | ![image](instructionImages/InitialVC.png) 41 | 42 | Make sure you have selected the table view controller and not the table view, otherwise you won't be able to find the setting in the inspector. The easiest way to ensure that the controller is selected is using the Document Outline in the left panel. In storyboard based applications the *Info.plist* file has an entry *Main storyboard file base name* that indicates the main storyboard file. The *initial* view controller within the *main* storyboard file is the one that will be displayed as root view controller. 43 | 44 | Now that we have configured a root view controller we can run the app for the first time and we should be able to see an empty list: 45 | 46 | ![image](instructionImages/EmpyList.png) 47 | 48 | The iPhone 6 and the iPhone 6 Plus Simulators have large screen sizes. If you are working on a Mac with a small screen you might want to downscale the iOS Simulator: 49 | 50 | ![image](instructionImages/Scale.png) 51 | 52 | ##Adding a Detail View Controller 53 | 54 | Now we'll add the view controller that will display the details of a selected Note. For this second view controller we will not use a template but instead start with a blank view controller. Select a *View Controller* from the Object Library in the bottom right and drag it to the storyboard. This blank view controller will become our Detail View Controller. For now we will just configure the high level navigation in our app, that means we won't fill the Detail View Controller with views just now. 55 | 56 | To complete the basic layout of our app we need to add a way to switch between the list and the detail view. Whenever an app has more than one view controller that we want to display, we need to use container view controllers that can handle multiple child view controllers and provide easy mechanics for users to switch between them. For the type of app we are creating now an `UINavigationViewController` is ideal. A `UINavigationViewController` maintains a stack of view Controllers. When we select an entry in the List View Controller we want to push our Detail View Controller for that entry. The navigation controller will create a back button in the top bar that can be used to easily navigate back to the list view. This navigation pattern provided by the `UINavigationViewController` is also incorporated in Apple's Mail and Messages app. 57 | 58 | ##Adding a Navigation View Controller 59 | 60 | Now that we know why we need a navigation view controller, let's add it to our storyboard. Fortunately Interface Builder provides a really easy way to add a navigation view controller to an existing storyboard. Select the table view controller, then select *Editor -> Embed In -> Navigation Controller*. 61 | 62 | ![image](instructionImages/EmbedNavigation.png) 63 | 64 | As you can see, Interface Builder creates a navigation controller and embeds the table view controller inside of it. It also automatically turns the navigation controller into the root view controller of the application, as indicated by the arrow pointing towards the navigation controller. With this setup the navigation controller is the root view controller of our application and the table view controller is the root view controller of the navigation view controller. We can run the app again: 65 | 66 | ![image](instructionImages/Navigation_TableView.png) 67 | 68 | Now you will see a navigation bar above the table view. This indicates that the table view is successfully embedded inside of a navigation controller. 69 | 70 | #Add Content to the App 71 | 72 | Now that we have the basic navigation set up we should start working on the actual content of our application. We will start with filling the first table view with entries. To create entries we will need to create a new class for our table view controller. This new class needs to be a subclass of `UITableViewController`. Then we will set up our table view controller in storyboard to use our custom class instead the default `UITableViewController` class. 73 | 74 | Create a new class by selecting *File -> New -> File...* 75 | 76 | ![image](instructionImages/NewFile.png) 77 | 78 | Name the new file `NotesListTableViewController` and make it a subclass of `UITableViewController`. Make sure the language is set to Swift. 79 | 80 | ![image](instructionImages/NotesListTableViewController.png) 81 | 82 | When Xcode creates the `NotesListTableViewController` it uses a template for `UITableViewController` subclasses that comes with a lot of comments and placeholder code. 83 | 84 | The `UITableView` is a very important component on the iOS platform, basically every scrollable list of items (e.g. messages, email) is implemented using `UITableView`. `UITableView` declares two protocols `UITableViewDataSource` and `UITableViewDelegate`. 85 | The data source protocol is used by the table view to determine the content it needs to display, the delegate protocol is used to inform another class about cells that have been selected and to provide an interface for modifying the table view behavior. 86 | 87 | The `UITableViewController` creates a `UITableView` and sets itself as the delegate and the data source of the table view. If you were to create a `ViewController` that has a table view and **does not** inherit from `UITableViewController` you would have to set up the data source and the delegate of your table view yourself. 88 | 89 | ##The UITableViewDataSource protocol 90 | 91 | A table view generates its content by asking its data source. The content of a table view is represented by `UITableViewCells`. Each row displays one of these cells. Additionally a `UITableView` can be divided into sections. Sections are represented by small headers between groups of cells. To determine the exact content a table view needs to display it polls its data source by calling the following methods: 92 | 93 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 94 | 95 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 96 | 97 | There are many more methods that are part of the protocol but the two mentioned above are required to be implemented and are sufficient to generate the basic content of the table view. By default a table view has one section. For our Notes app we will go with this default. If we would want to divide our content into multiple sections we would have to implement an additional data source method to report the amount of sections in our table view. 98 | 99 | Now lets fill the table view with some placeholder content: 100 | 101 | - Remove the `tableView(tableView:, numberOfSectionsInTableView:)` implementation from `NotesListTableViewController.swift`. Because we want to use the default option (one section) we do not need to implement this method 102 | - Change the implementation of `tableView(tableView:, numberOfRowsInSection:)` to return 10, for now we want display 10 placeholder cells in our list: 103 | 104 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 105 | // Return the number of rows in the section. 106 | return 10 107 | } 108 | 109 | - Add an implementation of `tableView(tableView:, cellForRowAtIndexPath:)`: 110 | 111 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 112 | var cell = tableView.dequeueReusableCellWithIdentifier("NotesCell", forIndexPath: indexPath) as UITableViewCell 113 | 114 | cell.textLabel!.text = "Note" 115 | 116 | return cell 117 | } 118 | 119 | The `tableView(tableView:, numberOfRowsInSection:)` implementation is quickly explained, the table view wants to know the amount of rows - for now we return 10 as a placeholder, later we will return the amount of notes we have stored in the app. 120 | 121 | The second method `tableView(tableView:, cellForRowAtIndexPath:)` is a little bit more complicated. To save memory a `UITableView` only keeps references to cells that are currently visible. Imagine how a list with 20,000 entries would impact memory and performance if the `UITableView` would create every cell upfront and keep a reference to it - dynamically allocating cells as they are needed is a better approach. Additionally the table view is designed to reuse cells that are no longer visible and to use them to display new content that has become visible - once again for performance reasons. This way a table view can use as little as 20 cells to display thousands of entries in a list. 122 | 123 | As developers we need to implement the `tableView(tableView:, cellForRowAtIndexPath:)` method in a way that reuses existing table view cells instead of constantly creating new ones. We accomplish this with the first line; we tell the table view to dequeue a cell with a certain *identifier*. The table view will try to reuse an existing cell that is currently not displayed, if that is not possible if will create a new one. We need this identifier because a table view could contain cells of different types (some cells could display places, other music, etc.) and we can only reuse an existing cell if it has the same type as the entry the table view is about to add. 124 | 125 | Luckily our app has only one cell type since we only display notes. Our code is now set up to display ten entries in our list. Before we can test this we need to set up some code connections. 126 | 127 | ##Code Connections 128 | 129 | We need two code connections in Interface Builder: 130 | 131 | - We need to set the *identifier* of our table view cell in our storyboard to the one that we have used in code 132 | - We need to set the custom class of the table view controller to `NotesListTableViewController` 133 | 134 | ###Table View Cell Identifier 135 | 136 | For this step open *Main.storyboard*. Interface Builder allows us to design different table view cells directly within the table view. These cells are listed under the header "Prototype Cells". Per default a table view has one prototype cell - just enough for our app. Select that prototype cell (you can use the Document Outline left pane, expand Table View Controller, then Table View and click Table View Cell) and set the *identifier* to *NotesCell* in the attributes inspector: 137 | 138 | ![image](instructionImages/CellIdentifier2.png) 139 | 140 | Now that the identifier we have set in code matches the one we have set up in our storyboard, the table view will now which type of cell it needs to instantiate. 141 | 142 | ##Setting up a Custom Class 143 | 144 | For the code in `NotesListTableViewController` to run, we need to set up a reference to it in our storyboard. We do that by setting up a custom class for our table view controller. Select the table view controller, then set the class in the identity inspector: 145 | 146 | ![image](instructionImages/CodeConnection.png) 147 | 148 | Now our custom class will be instantiated instead of the default `UITableViewController`. 149 | 150 | Now it's time to test the app again. Run it and you should see a list with 10 Entries: 151 | 152 | ![image](instructionImages/10Entries.png) 153 | 154 | #Connect the Detail View Controller 155 | 156 | Next, we want to connect the detail view controller with the list view controller, to complete our app navigation. Storyboard allows us to create these connections visually, they are called *segues*. We want to switch to the Detail View Controller when one of the cells in our list is tapped. Select the table view cell to set up a segue. Then select the rightmost tab in the right panel (Connections Inspector). In the *Triggered Segues* section you can see two different ways how a cell can trigger a transition to a different view controller, upon selection and upon accessory action. We want to transition upon selection, which allows the user to tap anywhere into the cell. We can create the segue by drag gin the mouse from the dot behind the triggered segue to the target view controller: 157 | 158 | ![image](instructionImages/Segue1.png) 159 | 160 | When we drop that connection we get to choose between different presentation types. We want to use *show* which is the default presentation type within a container view controller. 161 | 162 | ##Set up the Detail View Controller 163 | 164 | Our detail view controller will need some content. For this app we'll keep it simple - one textfield for the title of the note and a text view (supports multiple lines of text input) for the body of the note. Add a textfield to the top of the view and the text view below: 165 | 166 | ![image](instructionImages/DetailDesign.png) 167 | 168 | When you run this app you will see that the layout doesn't look that nice. Why? Starting with Xcode 6 we are strongly discouraged from defining User Interfaces with absolute positions, that is why Interface Builder is giving us a preview of our app in square dimensions. However the iPhone 6 is not square and the positions we have set up just don't work on an actual phone. So what is the solution? Auto Layout! 169 | Instead of using absolute positions, Auto Layout lets us define a set of constraints for our views. These constraints allow iOS to calculate absolute positions for different device types. Auto Layout is a whole chapter of its own, so we encourage you to take a look at the [Apple Auto Layout Guide](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/Introduction/Introduction.html). For now we will primarily take a look at how we can create layout constraints by creating a simple layout for our detail view. 170 | 171 | There are two easy ways to create constraints. First select any view from your storyboard. Then either select the *Pin* button in the right corner of the bottom bar, or hold the *Ctrl* key while dragging to another view. Layout constraints always express a relationship between two different layout elements by *Ctrl*-dragging you can easily choose between which views you want to establish a constraint. The *Pin* button in the bottom bar lets you create multiple constraints at once, but always automatically picks the closest neighbor to establish the constraint with: 172 | 173 | ![image](instructionImages/CreateConstraints.png) 174 | 175 | For our purposes the *Pin* button works better, since we only need to set up constraints between neighbors. 176 | Select the textfield and create three constraints. You can see that Interface Builder automatically suggests to create constraints with values based on the current position of the view, so you only need to activate the constraints by clicking onto them: 177 | 178 | ![image](instructionImages/textfieldConstraints.png) 179 | 180 | When you've set this up, select *Add 3 Constraints* at the bottom of the view. 181 | 182 | These constraints define that we want the text field to have a constant distance to the top of the superview and a constant distance to the left and right margins of the superview. This mean if the parent view resizes this textfield will grow/shrink accordingly. 183 | 184 | We want similar settings for our text view. Select the text view and add the following constraints: 185 | 186 | ![image](instructionImages/textviewConstraints.png) 187 | 188 | For the text view we need an additional constraint to define the distance between its top border and the bottom border of the text field. 189 | 190 | These constraints are sufficient for our app, they allow iOS to calculate the positions of our views based on the screen size. Time to run the app and see that the positioning looks good now. 191 | You can also test the layout in landscape mode and you will see that it looks good! 192 | 193 | ![image](instructionImages/ConstraintsDone.png) 194 | 195 | That is the power of Auto Layout. 196 | 197 | #Add Notes 198 | 199 | Now it's time to add some notes. Currently we are only displaying dummy data, that shall change in this step. 200 | 201 | Start off by creating a `Note` class. Go to File -> New -> File -> iOS -> Source -> Swift File 202 | 203 | ![image](instructionImages/NewSwiftFile.png) 204 | 205 | It should have the variables: `title` and `content`. 206 | 207 | class Note { 208 | var title = "" 209 | var content = "" 210 | } 211 | 212 | Once you have done that, let's create some notes in code and display them. Inside of `NotesListTableViewController` add the declaration for an array that will hold our notes: 213 | 214 | var notes: [Note] = [] 215 | 216 | Then implement `initWithCoder`, which is the designated initializer for view controllers that are created from storyboard files, and create notes and add them to the notes array: 217 | 218 | required init(coder aDecoder: NSCoder) { 219 | super.init(coder: aDecoder) 220 | 221 | var note1 = Note() 222 | note1.title = "Note 1" 223 | note1.content = "Note 1 content" 224 | 225 | var note2 = Note() 226 | note2.title = "Note 2" 227 | note2.content = "Note 2 content" 228 | 229 | var note3 = Note() 230 | note3.title = "Note 3" 231 | note3.content = "Note 3 content" 232 | 233 | notes.extend([note1, note2, note3]) 234 | } 235 | 236 | Now we have some real notes in our application! We can now change the implementation of our table view data source to use these notes instead of placeholder values. First change the implementation of `tableView(tableView:, numberOfRowsInSection:)`: 237 | 238 | override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 239 | // Return the number of rows in the section. 240 | return notes.count 241 | } 242 | 243 | Instead of returning a constant value of 10, we are now returning the actual amount of notes in our application. 244 | 245 | Now let's change the cell display code: 246 | 247 | override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 248 | var cell = tableView.dequeueReusableCellWithIdentifier("NotesCell", forIndexPath: indexPath) as UITableViewCell 249 | 250 | cell.textLabel!.text = notes[indexPath.row].title 251 | 252 | return cell 253 | } 254 | 255 | Instead of displaying a placeholder text we are now choosing one of our notes (based on which row the table view wants to display, which is passed in in the indexPath parameter) and display the title of that note. 256 | 257 | It's time to run the app again: 258 | 259 | ![image](instructionImages/realnotes.png) 260 | 261 | You can now see a list that is generated based on real data stored in our application. 262 | 263 | ##Passing Notes around 264 | 265 | Now that our list can display real `Note` objects we should add that capability to our detail view. This includes to steps: 266 | 267 | - Pass a Note that we have selected from the list to the Detail View Controller 268 | - Enable the Detail View Controller to display the Note using the title text field and the content text view 269 | 270 | Let's first create a custom class for our Detail View Controller, so that we can add a `note` variable that can be set by the list view controller. Go to File -> New -> File -> iOS -> Source -> Cocoa Touch Class. 271 | 272 | ![image](instructionImages/NewFile.png) 273 | 274 | Name the new class `NoteDetailViewController` and make it a subclass of `UIViewController`. Make sure it is a Swift class, not an Objective-C one. That class shall be able to store a `Note`, this is what it should look like: 275 | 276 | import UIKit 277 | 278 | class NoteDetailViewController: UIViewController { 279 | 280 | var note: Note! 281 | 282 | } 283 | 284 | Now that we have created this class, we need to set it up as a custom class for the Detail View Controller in our storyboard. Based on the previous example of setting up a custom class you should be able to solve this on your own! 285 | 286 | Now how can we hand the note to this Detail View Controller? Luckily UIKit provides a convenient method called `prepareForSegue(segue:, sender:)` that is called before a segue occurs. Here developers can access the `destinationViewController`, which is the view controller to which the segue is transitioning. 287 | 288 | We can implement that method in the `NotesListTableViewController` so that we can get access to the `NoteDetailViewController` we are transitioning to. 289 | 290 | Add this to *NotesListTableViewController.swift*: 291 | 292 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 293 | var noteDetailViewController = segue.destinationViewController as NoteDetailViewController 294 | var selectedIndexPath = tableView.indexPathForSelectedRow() 295 | noteDetailViewController.note = notes[selectedIndexPath!.row] 296 | } 297 | 298 | In the first line we are accessing the destination view controller of this segue, which is the `NoteDetailViewController`. In the next line we ask the table view which index path is currently selected. That allows us to determine which note has been selected in the list. In the last step we pick that note from our notes array and hand it to the detail view controller. 299 | 300 | Now we are successfully handing the note to the Detail View Controller - but we don't get to see much yet. Let's display the note in the detail view controller. 301 | 302 | ##Displaying a Note in the Detail View Controller 303 | 304 | We want to display the title of a note in the text field of the Detail View Controller and the content in the text view. To achieve that we need code connections to be able to change the content of our UI elements in code. Open the main storyboard and select the text field in the note Detail View Controller. Select the connections inspector in the right panel. This is the same tab that you used to trigger the segue from the table view cell to the Detail View Controller. Code connections that allow us to edit UI components from code are called *Referencing Outlets*. To create a code connection you need to switch to the *Assistant Editor* in the top right corner (red circle), that will allow you to display a interface file and code directly next to each other. Then you can drag the dot behind *New Referencing Outlet* into the *NoteDetailViewController.swift* file. 305 | 306 | ![image](instructionImages/IBOutlet1.png) 307 | 308 | When you end dragging the line a property will be created and you will be prompted for a name. Choose `titleTextField`: 309 | 310 | ![image](instructionImages/namingOutlet.png) 311 | 312 | Repeat the same for the text view and name the property `contentTextField`. 313 | Now we have two referencing outlets we can work with. Now we need an adequate place in code where we can display the currently selected note. A good method is `viewWillAppear(animated:):` which is called immediately before the view of a view controller is displayed. Add this implementation to *NoteDetailViewController.swift*: 314 | 315 | override func viewWillAppear(animated: Bool) { 316 | super.viewWillAppear(animated) 317 | 318 | titleTextField.text = note.title 319 | contentTextField.text = note.content 320 | } 321 | 322 | Now you can test the app and you will see that selected notes are passed to the Detail View Controller and displayed there. 323 | 324 | You will maybe realize that changes to the notes that you make in the detail view aren't saved. When you switch back to the List View Controller all changes to notes disappear. Luckily that is easily fixed. 325 | 326 | ##Storing changes to a note 327 | 328 | For the purpose of our small app storing changes to notes can be implemented very simple. Whenever the Detail View Controller disappears (which happens when a user hits the back button) we update the note with the current content displayed in our views. Can you guess how the method we are about to implement is called? Right - `viewWillDisappear(animated:)`: 329 | 330 | override func viewWillDisappear(animated: Bool) { 331 | super.viewWillDisappear(animated) 332 | 333 | note.title = titleTextField.text 334 | note.content = contentTextField.text 335 | } 336 | 337 | Now you will see that changes are persisted correctly. When switching back and forth between our two view controllers all changes we make in the Detail View Controller get displayed correctly. However, the list of notes always shows the old titles of our notes. 338 | 339 | ##Reloading a Table View 340 | 341 | The `UITableView` does not automatically refresh its content. In order to refresh the list we need to call `reloadData` on the table view (the `UITableViewController` calls `reloadData` once automatically when the table view is empty, that's why we only need to call it to refresh the table view content, not for the initial load). 342 | 343 | Once again a good place to trigger view updates is in the `viewWillAppear(animated:)` method. Add this method to *NotesListTableViewController.swift*: 344 | 345 | override func viewWillAppear(animated: Bool) { 346 | super.viewWillAppear(animated) 347 | 348 | tableView.reloadData() 349 | } 350 | 351 | Now we ask the table view to refresh its content every time it is displayed. This will trigger the table view to call the `tableView(tableView:, numberOfRowsInSection:)` and `tableView(tableView:, cellForRowAtIndexPath:)` methods on its data source, which is `NotesListTableViewController`. Here we will create cells that reflect the updated notes. 352 | 353 | Time to run the app once again. You should see notes updating and persisting in both view controllers correctly now. 354 | 355 | #Adding User Created Notes 356 | 357 | One of the main changes we need to make to complete this app is letting the user to create and delete notes. At the moment we are creating three notes in code and the user can only edit these. 358 | 359 | First we need to add a button that allows the user to create a new note. Let's add a *+* button to the List View Controller. A common place to place buttons within view controllers that are wrapped into a navigation controller is in the navigation bar at the top of the screen. This is also where the back button is placed automatically. 360 | 361 | Buttons for that top bar are called bar button items. Luckily UIKit already provides a *+* button style for us. Add a bar button item to the navigation bar and change the style to be a *+* button: 362 | 363 | ![image](instructionImages/barbutton_item.png) 364 | 365 | iOS apps stand out because of great usability. For our app it would be nice if the *+* button would create a new note and then display the same view controller that is used to display/edit notes. This way the user will only have to be familiar with two different view controllers. 366 | 367 | Let's add a segue from the *+* button to the detail view controller: 368 | 369 | ![image](instructionImages/addSegue.png) 370 | 371 | Choose this to be a *show* segue again. If you happen to test the *+* button now you will realize that a transition happens, but instead of creating a new note we are always displaying the first note in the list. Where could we implement creating a new note before we transition to the detail view controller? Right - in the `prepareForSegue(segue:, sender:)` method inside of `NotesListTableViewController`. 372 | 373 | Thinking about this you might realize that we now have two different segues that both transition from the list view controller to the detail view controller. In order to determine if we need to select an existing note for display or if we need to create a new note we need to know which of these two segues is currently going on. UIKit allows us to assign *identifiers* to segues, that allows us to implement different behavior for different segues. Let's assign two different identifiers to our segues. We can do so by selecting a segue in our storyboard and selecting the attributes inspector: 374 | 375 | ![image](instructionImages/nameSegue.png) 376 | 377 | Choose "addNote" as the identifier for the segue from the *+* button and "showNote" for the segue from the table view cell. 378 | Now we can identify the two different segues. Let's change the implementation of our `prepareForSegue(segue:, sender:)` method accordingly: 379 | 380 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 381 | if segue.identifier! == "showNote" { 382 | var noteDetailViewController = segue.destinationViewController as NoteDetailViewController 383 | var selectedIndexPath = tableView.indexPathForSelectedRow() 384 | noteDetailViewController.note = notes[selectedIndexPath!.row] 385 | } else if segue.identifier! == "addNote" { 386 | var note = Note() 387 | notes.append(note) 388 | var noteDetailViewController = segue.destinationViewController as NoteDetailViewController 389 | noteDetailViewController.note = note 390 | } 391 | } 392 | 393 | On a *Show Note* segue we are performing our old code, on a *Add Note* segue we are creating a new note, adding it to our array of notes and handing that new note to the detail view controller. Now a user is able to add custom notes to this app. If you feel like improving the app you could set up a default title and content for newly created notes. 394 | 395 | Now that a user can create notes we no longer need to create dummy ones. You can remove the whole ```initWithCoder``` method. 396 | 397 | #Deleting Notes 398 | 399 | The ability to delete notes is nearly as important as the one to add them. This will also be the last feature that we are adding to this app. Implementing a deletion mechanism is simple. The default delete gesture on iOS is swiping to the left on a table view cell. This can be implemented in our own apps by adding the `tableView(tableView:, commitEditingStyle:, forRowAtIndexPath:)` method that is part of the `UITableViewDataSource` protocol. 400 | 401 | The method gets called when the user attempts to delete an entry with the before mentioned gesture. It is the developers task to delete the according element from the data model and also trigger a visual deletion of the table view cell. Here is the two-liner implementation that does the deletion magic: 402 | 403 | override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 404 | notes.removeAtIndex(indexPath.row) 405 | tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) 406 | } 407 | 408 | The first line simply deletes the note from our notes array, now our data model is up to date. The second line updates the UI to reflect the deletion. The table view provides a convenience method to do that: `deleteRowsAtIndexPaths(indexPaths:, withRowAnimation:)`. 409 | Now you should be able to add, edit and delete notes! Well done. 410 | -------------------------------------------------------------------------------- /instructionImages/10Entries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/10Entries.png -------------------------------------------------------------------------------- /instructionImages/AppDetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/AppDetails.png -------------------------------------------------------------------------------- /instructionImages/AppTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/AppTemplate.png -------------------------------------------------------------------------------- /instructionImages/ApplicationType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/ApplicationType.png -------------------------------------------------------------------------------- /instructionImages/CellIdentifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/CellIdentifier.png -------------------------------------------------------------------------------- /instructionImages/CellIdentifier2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/CellIdentifier2.png -------------------------------------------------------------------------------- /instructionImages/CodeConnection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/CodeConnection.png -------------------------------------------------------------------------------- /instructionImages/ConstraintsDone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/ConstraintsDone.png -------------------------------------------------------------------------------- /instructionImages/CreateConstraints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/CreateConstraints.png -------------------------------------------------------------------------------- /instructionImages/Delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/Delete.png -------------------------------------------------------------------------------- /instructionImages/DetailDesign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/DetailDesign.png -------------------------------------------------------------------------------- /instructionImages/EmbedNavigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/EmbedNavigation.png -------------------------------------------------------------------------------- /instructionImages/EmpyList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/EmpyList.png -------------------------------------------------------------------------------- /instructionImages/IBOutlet1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/IBOutlet1.png -------------------------------------------------------------------------------- /instructionImages/InitialVC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/InitialVC.png -------------------------------------------------------------------------------- /instructionImages/Navigation_TableView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/Navigation_TableView.png -------------------------------------------------------------------------------- /instructionImages/NewFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/NewFile.png -------------------------------------------------------------------------------- /instructionImages/NewSwiftFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/NewSwiftFile.png -------------------------------------------------------------------------------- /instructionImages/NotesListTableViewController.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/NotesListTableViewController.png -------------------------------------------------------------------------------- /instructionImages/ObjectLibrary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/ObjectLibrary.png -------------------------------------------------------------------------------- /instructionImages/Scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/Scale.png -------------------------------------------------------------------------------- /instructionImages/Segue1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/Segue1.png -------------------------------------------------------------------------------- /instructionImages/addSegue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/addSegue.png -------------------------------------------------------------------------------- /instructionImages/barbutton_item.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/barbutton_item.png -------------------------------------------------------------------------------- /instructionImages/nameSegue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/nameSegue.png -------------------------------------------------------------------------------- /instructionImages/namingOutlet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/namingOutlet.png -------------------------------------------------------------------------------- /instructionImages/realnotes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/realnotes.png -------------------------------------------------------------------------------- /instructionImages/textfieldConstraints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/textfieldConstraints.png -------------------------------------------------------------------------------- /instructionImages/textviewConstraints.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakeSchool/iOS8-Notes-Swift/67726be843bd308d73b5fad6d339881476de0f32/instructionImages/textviewConstraints.png --------------------------------------------------------------------------------