├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── WeatherApp.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── WeatherApp ├── Application └── AppDelegate.swift ├── Controllers ├── CitiesViewController.swift └── CityViewController.swift ├── Helpers ├── DatabaseHelper.swift ├── NetworkingHelper.swift └── TranslatorHelper.swift ├── Images.xcassets ├── AppIcon.appiconset │ └── Contents.json └── LaunchImage.launchimage │ └── Contents.json ├── Models └── City.swift ├── Supporting └── Info.plist └── Views └── Main.storyboard /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by http://www.gitignore.io 2 | 3 | ### OSX ### 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear on external disk 16 | .Spotlight-V100 17 | .Trashes 18 | 19 | # Directories potentially created on remote AFP share 20 | .AppleDB 21 | .AppleDesktop 22 | Network Trash Folder 23 | Temporary Items 24 | .apdisk 25 | 26 | 27 | ### Swift ### 28 | # Xcode 29 | # 30 | build/ 31 | *.pbxuser 32 | !default.pbxuser 33 | *.mode1v3 34 | !default.mode1v3 35 | *.mode2v3 36 | !default.mode2v3 37 | *.perspectivev3 38 | !default.perspectivev3 39 | xcuserdata 40 | *.xccheckout 41 | *.moved-aside 42 | DerivedData 43 | *.hmap 44 | *.ipa 45 | *.xcuserstate 46 | 47 | # CocoaPods 48 | # 49 | # We recommend against adding the Pods directory to your .gitignore. However 50 | # you should judge for yourself, the pros and cons are mentioned at: 51 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 52 | # 53 | # Pods/ 54 | 55 | 56 | ### Xcode ### 57 | build/ 58 | *.pbxuser 59 | !default.pbxuser 60 | *.mode1v3 61 | !default.mode1v3 62 | *.mode2v3 63 | !default.mode2v3 64 | *.perspectivev3 65 | !default.perspectivev3 66 | xcuserdata 67 | *.xccheckout 68 | *.moved-aside 69 | DerivedData 70 | *.xcuserstate 71 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "External/Alamofire"] 2 | path = External/Alamofire 3 | url = git@github.com:Alamofire/Alamofire.git 4 | [submodule "External/SwiftyJSON"] 5 | path = External/SwiftyJSON 6 | url = git@github.com:lingoer/SwiftyJSON.git 7 | [submodule "External/realm-cocoa"] 8 | path = External/realm-cocoa 9 | url = git@github.com:realm/realm-cocoa.git 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Renzo Crisóstomo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ios-swift-example 2 | ================= 3 | 4 | __Description:__ 5 | 6 | This is an iOS application example written in Swift using Alamofire networking library, Realm mobile database library and SwiftyJSON JSON parsing library. 7 | 8 | ![ios-swift-screenshot-1.png](https://raw.githubusercontent.com/Ruenzuo/res/master/ios-swift-screenshot-1.png)  9 | ![ios-swift-screenshot-2.png](https://raw.githubusercontent.com/Ruenzuo/res/master/ios-swift-screenshot-2.png) 10 | 11 | __Building:__ 12 | 13 | In order to build the application, clone this repo recursively and open the project file: 14 | 15 | ```sh 16 | $ git clone git@github.com:Ruenzuo/ios-swift-example.git --recursive && open WeatherApp.xcodeproj 17 | ``` 18 | 19 | __Notes:__ 20 | 21 | * This project was made in Xcode6-Beta5, compatibility is not guaranteed in previous or future versions. 22 | 23 | License 24 | ======= 25 | 26 | The MIT License (MIT) 27 | 28 | Copyright (c) 2014 Renzo Crisóstomo 29 | 30 | Permission is hereby granted, free of charge, to any person obtaining a copy of 31 | this software and associated documentation files (the "Software"), to deal in 32 | the Software without restriction, including without limitation the rights to 33 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 34 | the Software, and to permit persons to whom the Software is furnished to do so, 35 | subject to the following conditions: 36 | 37 | The above copyright notice and this permission notice shall be included in all 38 | copies or substantial portions of the Software. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 42 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 43 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 44 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 45 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 46 | -------------------------------------------------------------------------------- /WeatherApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A0231905199C8EA20014A59F /* Realm.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A02318F4199C8E710014A59F /* Realm.framework */; }; 11 | A0231908199C8ED20014A59F /* Realm.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = A02318F8199C8E710014A59F /* Realm.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 12 | A023190A199C94230014A59F /* DatabaseHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0231909199C94230014A59F /* DatabaseHelper.swift */; }; 13 | A0391B8C199A134F003E93EB /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A0391B8B199A134F003E93EB /* Images.xcassets */; }; 14 | A0391BA7199A14CE003E93EB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0391BA6199A14CE003E93EB /* AppDelegate.swift */; }; 15 | A0391BAB199A14E8003E93EB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A0391BAA199A14E8003E93EB /* Main.storyboard */; }; 16 | A0F5EAC4199A1F770079BD9E /* NetworkingHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F5EAC3199A1F770079BD9E /* NetworkingHelper.swift */; }; 17 | A0F5EAC6199A23610079BD9E /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0F5EAC5199A23610079BD9E /* CoreLocation.framework */; }; 18 | A0F5EACA199A2CAA0079BD9E /* TranslatorHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F5EAC9199A2CAA0079BD9E /* TranslatorHelper.swift */; }; 19 | A0F5EACC199A2EC90079BD9E /* Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F5EACB199A2EC90079BD9E /* Alamofire.swift */; }; 20 | A0F5EACE199A2EEE0079BD9E /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F5EACD199A2EEE0079BD9E /* SwiftyJSON.swift */; }; 21 | A0F5EAD1199A2F740079BD9E /* City.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F5EAD0199A2F740079BD9E /* City.swift */; }; 22 | A0F5EAD3199A2FC40079BD9E /* CitiesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F5EAD2199A2FC40079BD9E /* CitiesViewController.swift */; }; 23 | A0F5EAD5199A3CB20079BD9E /* CityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F5EAD4199A3CB20079BD9E /* CityViewController.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXContainerItemProxy section */ 27 | A02318F3199C8E710014A59F /* PBXContainerItemProxy */ = { 28 | isa = PBXContainerItemProxy; 29 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 30 | proxyType = 2; 31 | remoteGlobalIDString = E8D89B981955FC6D00CF2B9A; 32 | remoteInfo = OSX; 33 | }; 34 | A02318F5199C8E710014A59F /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 37 | proxyType = 2; 38 | remoteGlobalIDString = E8D89BA31955FC6D00CF2B9A; 39 | remoteInfo = "OSX Tests"; 40 | }; 41 | A02318F7199C8E710014A59F /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 44 | proxyType = 2; 45 | remoteGlobalIDString = E856D1D5195614A300FB2FCF; 46 | remoteInfo = iOS; 47 | }; 48 | A02318F9199C8E710014A59F /* PBXContainerItemProxy */ = { 49 | isa = PBXContainerItemProxy; 50 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 51 | proxyType = 2; 52 | remoteGlobalIDString = E856D1DF195614A400FB2FCF; 53 | remoteInfo = "iOS Tests"; 54 | }; 55 | A02318FB199C8E710014A59F /* PBXContainerItemProxy */ = { 56 | isa = PBXContainerItemProxy; 57 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 58 | proxyType = 2; 59 | remoteGlobalIDString = 3F8DCA5719930F550008BD7F; 60 | remoteInfo = "iOS Device Tests"; 61 | }; 62 | A02318FD199C8E710014A59F /* PBXContainerItemProxy */ = { 63 | isa = PBXContainerItemProxy; 64 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 65 | proxyType = 2; 66 | remoteGlobalIDString = E8FE4140196DBA6700073FBB; 67 | remoteInfo = OSXTestFramework; 68 | }; 69 | A02318FF199C8E710014A59F /* PBXContainerItemProxy */ = { 70 | isa = PBXContainerItemProxy; 71 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 72 | proxyType = 2; 73 | remoteGlobalIDString = E8CA10F9196DC18A0044F8AA; 74 | remoteInfo = iOSTestFramework; 75 | }; 76 | A0231901199C8E710014A59F /* PBXContainerItemProxy */ = { 77 | isa = PBXContainerItemProxy; 78 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 79 | proxyType = 2; 80 | remoteGlobalIDString = 3F1A5E721992EB7400F45F4C; 81 | remoteInfo = TestHost; 82 | }; 83 | A0231903199C8E930014A59F /* PBXContainerItemProxy */ = { 84 | isa = PBXContainerItemProxy; 85 | containerPortal = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 86 | proxyType = 1; 87 | remoteGlobalIDString = E856D1D4195614A300FB2FCF; 88 | remoteInfo = iOS; 89 | }; 90 | /* End PBXContainerItemProxy section */ 91 | 92 | /* Begin PBXCopyFilesBuildPhase section */ 93 | A0231906199C8EAB0014A59F /* CopyFiles */ = { 94 | isa = PBXCopyFilesBuildPhase; 95 | buildActionMask = 2147483647; 96 | dstPath = ""; 97 | dstSubfolderSpec = 10; 98 | files = ( 99 | A0231908199C8ED20014A59F /* Realm.framework in CopyFiles */, 100 | ); 101 | runOnlyForDeploymentPostprocessing = 0; 102 | }; 103 | /* End PBXCopyFilesBuildPhase section */ 104 | 105 | /* Begin PBXFileReference section */ 106 | A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "Realm-Xcode6.xcodeproj"; path = "External/realm-cocoa/Realm-Xcode6.xcodeproj"; sourceTree = SOURCE_ROOT; }; 107 | A0231909199C94230014A59F /* DatabaseHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DatabaseHelper.swift; path = Helpers/DatabaseHelper.swift; sourceTree = ""; }; 108 | A0391B7F199A134F003E93EB /* WeatherApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WeatherApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 109 | A0391B8B199A134F003E93EB /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 110 | A0391BA1199A1498003E93EB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Supporting/Info.plist; sourceTree = ""; }; 111 | A0391BA6199A14CE003E93EB /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Application/AppDelegate.swift; sourceTree = ""; }; 112 | A0391BAA199A14E8003E93EB /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Views/Main.storyboard; sourceTree = ""; }; 113 | A0F5EAC3199A1F770079BD9E /* NetworkingHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NetworkingHelper.swift; path = Helpers/NetworkingHelper.swift; sourceTree = ""; }; 114 | A0F5EAC5199A23610079BD9E /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; 115 | A0F5EAC9199A2CAA0079BD9E /* TranslatorHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TranslatorHelper.swift; path = Helpers/TranslatorHelper.swift; sourceTree = ""; }; 116 | A0F5EACB199A2EC90079BD9E /* Alamofire.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Alamofire.swift; path = External/Alamofire/Source/Alamofire.swift; sourceTree = SOURCE_ROOT; }; 117 | A0F5EACD199A2EEE0079BD9E /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyJSON.swift; path = External/SwiftyJSON/SwiftyJSON/SwiftyJSON.swift; sourceTree = SOURCE_ROOT; }; 118 | A0F5EAD0199A2F740079BD9E /* City.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = City.swift; path = Models/City.swift; sourceTree = ""; }; 119 | A0F5EAD2199A2FC40079BD9E /* CitiesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CitiesViewController.swift; path = Controllers/CitiesViewController.swift; sourceTree = ""; }; 120 | A0F5EAD4199A3CB20079BD9E /* CityViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CityViewController.swift; path = Controllers/CityViewController.swift; sourceTree = ""; }; 121 | /* End PBXFileReference section */ 122 | 123 | /* Begin PBXFrameworksBuildPhase section */ 124 | A0391B7C199A134F003E93EB /* Frameworks */ = { 125 | isa = PBXFrameworksBuildPhase; 126 | buildActionMask = 2147483647; 127 | files = ( 128 | A0231905199C8EA20014A59F /* Realm.framework in Frameworks */, 129 | A0F5EAC6199A23610079BD9E /* CoreLocation.framework in Frameworks */, 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | /* End PBXFrameworksBuildPhase section */ 134 | 135 | /* Begin PBXGroup section */ 136 | A02318E9199C8E710014A59F /* Products */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | A02318F4199C8E710014A59F /* Realm.framework */, 140 | A02318F6199C8E710014A59F /* OSX Tests.xctest */, 141 | A02318F8199C8E710014A59F /* Realm.framework */, 142 | A02318FA199C8E710014A59F /* iOS Tests.xctest */, 143 | A02318FC199C8E710014A59F /* iOS Device Tests.xctest */, 144 | A02318FE199C8E710014A59F /* TestFramework.framework */, 145 | A0231900199C8E710014A59F /* TestFramework.framework */, 146 | A0231902199C8E710014A59F /* TestHost.app */, 147 | ); 148 | name = Products; 149 | sourceTree = ""; 150 | }; 151 | A0391B76199A134F003E93EB = { 152 | isa = PBXGroup; 153 | children = ( 154 | A0391B81199A134F003E93EB /* WeatherApp */, 155 | A0391B80199A134F003E93EB /* Products */, 156 | ); 157 | sourceTree = ""; 158 | }; 159 | A0391B80199A134F003E93EB /* Products */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | A0391B7F199A134F003E93EB /* WeatherApp.app */, 163 | ); 164 | name = Products; 165 | sourceTree = ""; 166 | }; 167 | A0391B81199A134F003E93EB /* WeatherApp */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | A0391BA3199A14AE003E93EB /* Application */, 171 | A0391BA5199A14C1003E93EB /* Controllers */, 172 | A0F5EABF199A17490079BD9E /* External */, 173 | A0F5EAC8199A237D0079BD9E /* Frameworks */, 174 | A0F5EAC2199A1F370079BD9E /* Helpers */, 175 | A0391B8B199A134F003E93EB /* Images.xcassets */, 176 | A0F5EACF199A2F390079BD9E /* Models */, 177 | A0391B82199A134F003E93EB /* Supporting */, 178 | A0391BA4199A14B7003E93EB /* Views */, 179 | ); 180 | path = WeatherApp; 181 | sourceTree = ""; 182 | }; 183 | A0391B82199A134F003E93EB /* Supporting */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | A0391BA1199A1498003E93EB /* Info.plist */, 187 | ); 188 | name = Supporting; 189 | sourceTree = ""; 190 | }; 191 | A0391BA3199A14AE003E93EB /* Application */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | A0391BA6199A14CE003E93EB /* AppDelegate.swift */, 195 | ); 196 | name = Application; 197 | sourceTree = ""; 198 | }; 199 | A0391BA4199A14B7003E93EB /* Views */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | A0391BAA199A14E8003E93EB /* Main.storyboard */, 203 | ); 204 | name = Views; 205 | sourceTree = ""; 206 | }; 207 | A0391BA5199A14C1003E93EB /* Controllers */ = { 208 | isa = PBXGroup; 209 | children = ( 210 | A0F5EAD2199A2FC40079BD9E /* CitiesViewController.swift */, 211 | A0F5EAD4199A3CB20079BD9E /* CityViewController.swift */, 212 | ); 213 | name = Controllers; 214 | sourceTree = ""; 215 | }; 216 | A0F5EABF199A17490079BD9E /* External */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | A0F5EACD199A2EEE0079BD9E /* SwiftyJSON.swift */, 220 | A0F5EACB199A2EC90079BD9E /* Alamofire.swift */, 221 | A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */, 222 | ); 223 | name = External; 224 | sourceTree = ""; 225 | }; 226 | A0F5EAC2199A1F370079BD9E /* Helpers */ = { 227 | isa = PBXGroup; 228 | children = ( 229 | A0F5EAC3199A1F770079BD9E /* NetworkingHelper.swift */, 230 | A0F5EAC9199A2CAA0079BD9E /* TranslatorHelper.swift */, 231 | A0231909199C94230014A59F /* DatabaseHelper.swift */, 232 | ); 233 | name = Helpers; 234 | sourceTree = ""; 235 | }; 236 | A0F5EAC8199A237D0079BD9E /* Frameworks */ = { 237 | isa = PBXGroup; 238 | children = ( 239 | A0F5EAC5199A23610079BD9E /* CoreLocation.framework */, 240 | ); 241 | name = Frameworks; 242 | sourceTree = ""; 243 | }; 244 | A0F5EACF199A2F390079BD9E /* Models */ = { 245 | isa = PBXGroup; 246 | children = ( 247 | A0F5EAD0199A2F740079BD9E /* City.swift */, 248 | ); 249 | name = Models; 250 | sourceTree = ""; 251 | }; 252 | /* End PBXGroup section */ 253 | 254 | /* Begin PBXNativeTarget section */ 255 | A0391B7E199A134F003E93EB /* WeatherApp */ = { 256 | isa = PBXNativeTarget; 257 | buildConfigurationList = A0391B9B199A134F003E93EB /* Build configuration list for PBXNativeTarget "WeatherApp" */; 258 | buildPhases = ( 259 | A0391B7B199A134F003E93EB /* Sources */, 260 | A0391B7C199A134F003E93EB /* Frameworks */, 261 | A0391B7D199A134F003E93EB /* Resources */, 262 | A0231906199C8EAB0014A59F /* CopyFiles */, 263 | ); 264 | buildRules = ( 265 | ); 266 | dependencies = ( 267 | A0231904199C8E930014A59F /* PBXTargetDependency */, 268 | ); 269 | name = WeatherApp; 270 | productName = WeatherApp; 271 | productReference = A0391B7F199A134F003E93EB /* WeatherApp.app */; 272 | productType = "com.apple.product-type.application"; 273 | }; 274 | /* End PBXNativeTarget section */ 275 | 276 | /* Begin PBXProject section */ 277 | A0391B77199A134F003E93EB /* Project object */ = { 278 | isa = PBXProject; 279 | attributes = { 280 | LastUpgradeCheck = 0600; 281 | ORGANIZATIONNAME = "Renzo Crisóstomo"; 282 | TargetAttributes = { 283 | A0391B7E199A134F003E93EB = { 284 | CreatedOnToolsVersion = 6.0; 285 | }; 286 | }; 287 | }; 288 | buildConfigurationList = A0391B7A199A134F003E93EB /* Build configuration list for PBXProject "WeatherApp" */; 289 | compatibilityVersion = "Xcode 3.2"; 290 | developmentRegion = English; 291 | hasScannedForEncodings = 0; 292 | knownRegions = ( 293 | en, 294 | Base, 295 | ); 296 | mainGroup = A0391B76199A134F003E93EB; 297 | productRefGroup = A0391B80199A134F003E93EB /* Products */; 298 | projectDirPath = ""; 299 | projectReferences = ( 300 | { 301 | ProductGroup = A02318E9199C8E710014A59F /* Products */; 302 | ProjectRef = A02318E8199C8E710014A59F /* Realm-Xcode6.xcodeproj */; 303 | }, 304 | ); 305 | projectRoot = ""; 306 | targets = ( 307 | A0391B7E199A134F003E93EB /* WeatherApp */, 308 | ); 309 | }; 310 | /* End PBXProject section */ 311 | 312 | /* Begin PBXReferenceProxy section */ 313 | A02318F4199C8E710014A59F /* Realm.framework */ = { 314 | isa = PBXReferenceProxy; 315 | fileType = wrapper.framework; 316 | path = Realm.framework; 317 | remoteRef = A02318F3199C8E710014A59F /* PBXContainerItemProxy */; 318 | sourceTree = BUILT_PRODUCTS_DIR; 319 | }; 320 | A02318F6199C8E710014A59F /* OSX Tests.xctest */ = { 321 | isa = PBXReferenceProxy; 322 | fileType = wrapper.cfbundle; 323 | path = "OSX Tests.xctest"; 324 | remoteRef = A02318F5199C8E710014A59F /* PBXContainerItemProxy */; 325 | sourceTree = BUILT_PRODUCTS_DIR; 326 | }; 327 | A02318F8199C8E710014A59F /* Realm.framework */ = { 328 | isa = PBXReferenceProxy; 329 | fileType = wrapper.framework; 330 | path = Realm.framework; 331 | remoteRef = A02318F7199C8E710014A59F /* PBXContainerItemProxy */; 332 | sourceTree = BUILT_PRODUCTS_DIR; 333 | }; 334 | A02318FA199C8E710014A59F /* iOS Tests.xctest */ = { 335 | isa = PBXReferenceProxy; 336 | fileType = wrapper.cfbundle; 337 | path = "iOS Tests.xctest"; 338 | remoteRef = A02318F9199C8E710014A59F /* PBXContainerItemProxy */; 339 | sourceTree = BUILT_PRODUCTS_DIR; 340 | }; 341 | A02318FC199C8E710014A59F /* iOS Device Tests.xctest */ = { 342 | isa = PBXReferenceProxy; 343 | fileType = wrapper.cfbundle; 344 | path = "iOS Device Tests.xctest"; 345 | remoteRef = A02318FB199C8E710014A59F /* PBXContainerItemProxy */; 346 | sourceTree = BUILT_PRODUCTS_DIR; 347 | }; 348 | A02318FE199C8E710014A59F /* TestFramework.framework */ = { 349 | isa = PBXReferenceProxy; 350 | fileType = wrapper.framework; 351 | path = TestFramework.framework; 352 | remoteRef = A02318FD199C8E710014A59F /* PBXContainerItemProxy */; 353 | sourceTree = BUILT_PRODUCTS_DIR; 354 | }; 355 | A0231900199C8E710014A59F /* TestFramework.framework */ = { 356 | isa = PBXReferenceProxy; 357 | fileType = wrapper.framework; 358 | path = TestFramework.framework; 359 | remoteRef = A02318FF199C8E710014A59F /* PBXContainerItemProxy */; 360 | sourceTree = BUILT_PRODUCTS_DIR; 361 | }; 362 | A0231902199C8E710014A59F /* TestHost.app */ = { 363 | isa = PBXReferenceProxy; 364 | fileType = wrapper.application; 365 | path = TestHost.app; 366 | remoteRef = A0231901199C8E710014A59F /* PBXContainerItemProxy */; 367 | sourceTree = BUILT_PRODUCTS_DIR; 368 | }; 369 | /* End PBXReferenceProxy section */ 370 | 371 | /* Begin PBXResourcesBuildPhase section */ 372 | A0391B7D199A134F003E93EB /* Resources */ = { 373 | isa = PBXResourcesBuildPhase; 374 | buildActionMask = 2147483647; 375 | files = ( 376 | A0391BAB199A14E8003E93EB /* Main.storyboard in Resources */, 377 | A0391B8C199A134F003E93EB /* Images.xcassets in Resources */, 378 | ); 379 | runOnlyForDeploymentPostprocessing = 0; 380 | }; 381 | /* End PBXResourcesBuildPhase section */ 382 | 383 | /* Begin PBXSourcesBuildPhase section */ 384 | A0391B7B199A134F003E93EB /* Sources */ = { 385 | isa = PBXSourcesBuildPhase; 386 | buildActionMask = 2147483647; 387 | files = ( 388 | A0F5EAC4199A1F770079BD9E /* NetworkingHelper.swift in Sources */, 389 | A023190A199C94230014A59F /* DatabaseHelper.swift in Sources */, 390 | A0F5EACC199A2EC90079BD9E /* Alamofire.swift in Sources */, 391 | A0F5EACA199A2CAA0079BD9E /* TranslatorHelper.swift in Sources */, 392 | A0F5EAD5199A3CB20079BD9E /* CityViewController.swift in Sources */, 393 | A0F5EACE199A2EEE0079BD9E /* SwiftyJSON.swift in Sources */, 394 | A0391BA7199A14CE003E93EB /* AppDelegate.swift in Sources */, 395 | A0F5EAD3199A2FC40079BD9E /* CitiesViewController.swift in Sources */, 396 | A0F5EAD1199A2F740079BD9E /* City.swift in Sources */, 397 | ); 398 | runOnlyForDeploymentPostprocessing = 0; 399 | }; 400 | /* End PBXSourcesBuildPhase section */ 401 | 402 | /* Begin PBXTargetDependency section */ 403 | A0231904199C8E930014A59F /* PBXTargetDependency */ = { 404 | isa = PBXTargetDependency; 405 | name = iOS; 406 | targetProxy = A0231903199C8E930014A59F /* PBXContainerItemProxy */; 407 | }; 408 | /* End PBXTargetDependency section */ 409 | 410 | /* Begin XCBuildConfiguration section */ 411 | A0391B99199A134F003E93EB /* Debug */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ALWAYS_SEARCH_USER_PATHS = NO; 415 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 416 | CLANG_CXX_LIBRARY = "libc++"; 417 | CLANG_ENABLE_MODULES = YES; 418 | CLANG_ENABLE_OBJC_ARC = YES; 419 | CLANG_WARN_BOOL_CONVERSION = YES; 420 | CLANG_WARN_CONSTANT_CONVERSION = YES; 421 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 422 | CLANG_WARN_EMPTY_BODY = YES; 423 | CLANG_WARN_ENUM_CONVERSION = YES; 424 | CLANG_WARN_INT_CONVERSION = YES; 425 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 426 | CLANG_WARN_UNREACHABLE_CODE = YES; 427 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 428 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 429 | COPY_PHASE_STRIP = NO; 430 | ENABLE_STRICT_OBJC_MSGSEND = YES; 431 | GCC_C_LANGUAGE_STANDARD = gnu99; 432 | GCC_DYNAMIC_NO_PIC = NO; 433 | GCC_OPTIMIZATION_LEVEL = 0; 434 | GCC_PREPROCESSOR_DEFINITIONS = ( 435 | "DEBUG=1", 436 | "$(inherited)", 437 | ); 438 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 439 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 440 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 441 | GCC_WARN_UNDECLARED_SELECTOR = YES; 442 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 443 | GCC_WARN_UNUSED_FUNCTION = YES; 444 | GCC_WARN_UNUSED_VARIABLE = YES; 445 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 446 | MTL_ENABLE_DEBUG_INFO = YES; 447 | ONLY_ACTIVE_ARCH = YES; 448 | SDKROOT = iphoneos; 449 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 450 | }; 451 | name = Debug; 452 | }; 453 | A0391B9A199A134F003E93EB /* Release */ = { 454 | isa = XCBuildConfiguration; 455 | buildSettings = { 456 | ALWAYS_SEARCH_USER_PATHS = NO; 457 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 458 | CLANG_CXX_LIBRARY = "libc++"; 459 | CLANG_ENABLE_MODULES = YES; 460 | CLANG_ENABLE_OBJC_ARC = YES; 461 | CLANG_WARN_BOOL_CONVERSION = YES; 462 | CLANG_WARN_CONSTANT_CONVERSION = YES; 463 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 464 | CLANG_WARN_EMPTY_BODY = YES; 465 | CLANG_WARN_ENUM_CONVERSION = YES; 466 | CLANG_WARN_INT_CONVERSION = YES; 467 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 468 | CLANG_WARN_UNREACHABLE_CODE = YES; 469 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 470 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 471 | COPY_PHASE_STRIP = YES; 472 | ENABLE_NS_ASSERTIONS = NO; 473 | ENABLE_STRICT_OBJC_MSGSEND = YES; 474 | GCC_C_LANGUAGE_STANDARD = gnu99; 475 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 476 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 477 | GCC_WARN_UNDECLARED_SELECTOR = YES; 478 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 479 | GCC_WARN_UNUSED_FUNCTION = YES; 480 | GCC_WARN_UNUSED_VARIABLE = YES; 481 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 482 | MTL_ENABLE_DEBUG_INFO = NO; 483 | SDKROOT = iphoneos; 484 | VALIDATE_PRODUCT = YES; 485 | }; 486 | name = Release; 487 | }; 488 | A0391B9C199A134F003E93EB /* Debug */ = { 489 | isa = XCBuildConfiguration; 490 | buildSettings = { 491 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 492 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 493 | DEFINES_MODULE = YES; 494 | INFOPLIST_FILE = "$(SRCROOT)/WeatherApp/Supporting/Info.plist"; 495 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 496 | PRODUCT_NAME = "$(TARGET_NAME)"; 497 | }; 498 | name = Debug; 499 | }; 500 | A0391B9D199A134F003E93EB /* Release */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 504 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 505 | DEFINES_MODULE = YES; 506 | INFOPLIST_FILE = "$(SRCROOT)/WeatherApp/Supporting/Info.plist"; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 508 | PRODUCT_NAME = "$(TARGET_NAME)"; 509 | }; 510 | name = Release; 511 | }; 512 | /* End XCBuildConfiguration section */ 513 | 514 | /* Begin XCConfigurationList section */ 515 | A0391B7A199A134F003E93EB /* Build configuration list for PBXProject "WeatherApp" */ = { 516 | isa = XCConfigurationList; 517 | buildConfigurations = ( 518 | A0391B99199A134F003E93EB /* Debug */, 519 | A0391B9A199A134F003E93EB /* Release */, 520 | ); 521 | defaultConfigurationIsVisible = 0; 522 | defaultConfigurationName = Release; 523 | }; 524 | A0391B9B199A134F003E93EB /* Build configuration list for PBXNativeTarget "WeatherApp" */ = { 525 | isa = XCConfigurationList; 526 | buildConfigurations = ( 527 | A0391B9C199A134F003E93EB /* Debug */, 528 | A0391B9D199A134F003E93EB /* Release */, 529 | ); 530 | defaultConfigurationIsVisible = 0; 531 | defaultConfigurationName = Release; 532 | }; 533 | /* End XCConfigurationList section */ 534 | }; 535 | rootObject = A0391B77199A134F003E93EB /* Project object */; 536 | } 537 | -------------------------------------------------------------------------------- /WeatherApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WeatherApp/Application/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // WeatherApp 4 | // 5 | // Created by Renzo Crisostomo on 12/08/14. 6 | // Copyright (c) 2014 Renzo Crisóstomo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool { 18 | return true 19 | } 20 | 21 | } 22 | 23 | -------------------------------------------------------------------------------- /WeatherApp/Controllers/CitiesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CitiesViewController.swift 3 | // WeatherApp 4 | // 5 | // Created by Renzo Crisostomo on 12/08/14. 6 | // Copyright (c) 2014 Renzo Crisóstomo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreLocation 11 | import Realm 12 | 13 | class CitiesViewController: UITableViewController, CLLocationManagerDelegate, UITableViewDataSource, UITableViewDelegate, UIAlertViewDelegate { 14 | 15 | let tableViewCellIdentifier = "CityCell" 16 | let showCitySegueIdentifier = "ShowCity" 17 | let networkingHelper = NetworkingHelper() 18 | let locationManager = CLLocationManager() 19 | let databaseHelper = DatabaseHelper() 20 | var cities = RLMArray(objectClassName: "City") 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | setupRefreshControl() 25 | setupLocationManager() 26 | } 27 | 28 | override func didReceiveMemoryWarning() { 29 | super.didReceiveMemoryWarning() 30 | } 31 | 32 | override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { 33 | if (segue.identifier == showCitySegueIdentifier) { 34 | let destination = segue.destinationViewController as CityViewController 35 | let city = cities[UInt(self.tableView.indexPathForSelectedRow().row)] as City 36 | destination.city = city 37 | } 38 | } 39 | 40 | func setupLocationManager() { 41 | locationManager.delegate = self 42 | locationManager.requestWhenInUseAuthorization() 43 | } 44 | 45 | func setupRefreshControl() { 46 | let refreshControl = UIRefreshControl() 47 | refreshControl.addTarget(self, action: Selector("onRefresh:"), forControlEvents: UIControlEvents.ValueChanged) 48 | self.refreshControl = refreshControl 49 | } 50 | 51 | func onRefresh(sender: AnyObject!) { 52 | if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.AuthorizedWhenInUse { 53 | locationManager.startUpdatingLocation() 54 | } else { 55 | refreshControl.endRefreshing() 56 | let alert = UIAlertView(title: "Authorization required", message: "Please, authorize location in settings.", delegate: nil, cancelButtonTitle: "OK") 57 | alert.show() 58 | } 59 | } 60 | 61 | func loadCitiesWithUserLatitude(userLatitude: Double, userLongitude: Double) { 62 | networkingHelper.citiesWithUserLatitude(userLatitude, userLongitude: userLongitude) { (cities, error) -> () in 63 | self.refreshControl.endRefreshing() 64 | if let unwrappedError = error? { 65 | if unwrappedError.domain == NSURLErrorDomain && unwrappedError.code == NSURLErrorNotConnectedToInternet { 66 | let alertView = UIAlertView(title: "Error", message: "Internet connection appears to be offline. Would you like to retrieve the last stored values?", delegate: self, cancelButtonTitle: "No", otherButtonTitles: "Yes") 67 | alertView.show() 68 | } 69 | } else { 70 | self.databaseHelper.storeCities(cities!) 71 | self.loadCitiesFromDatabase() 72 | } 73 | } 74 | } 75 | 76 | func loadCitiesFromDatabase() { 77 | cities = City.allObjects() 78 | self.tableView.reloadData() 79 | } 80 | 81 | // MARK: - CLLocationManagerDelegate 82 | 83 | func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { 84 | if locations.count > 0 { 85 | let location: CLLocation = locations.first! as CLLocation 86 | locationManager.stopUpdatingLocation() 87 | loadCitiesWithUserLatitude(location.coordinate.latitude, userLongitude: location.coordinate.longitude) 88 | } 89 | } 90 | 91 | func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) { 92 | if status == CLAuthorizationStatus.AuthorizedWhenInUse { 93 | onRefresh(self.refreshControl) 94 | } 95 | } 96 | 97 | // MARK: - UITableViewDataSource 98 | 99 | override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { 100 | return Int(cities.count) 101 | } 102 | 103 | override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { 104 | let tableViewCell = tableView.dequeueReusableCellWithIdentifier(tableViewCellIdentifier, forIndexPath: indexPath) as UITableViewCell 105 | let city = cities[UInt(indexPath.row)] as City 106 | tableViewCell.textLabel.text = city.name 107 | return tableViewCell 108 | } 109 | 110 | // MARK: - UITableViewDelegate 111 | 112 | override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) { 113 | performSegueWithIdentifier(showCitySegueIdentifier, sender: self) 114 | } 115 | 116 | // MARK: - UIAlertViewDelegate 117 | 118 | func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int) { 119 | // alertView.firstOtherButtonIndex is not working as for Beta 5. 120 | if (1 == buttonIndex) { 121 | loadCitiesFromDatabase() 122 | } 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /WeatherApp/Controllers/CityViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CityViewController.swift 3 | // WeatherApp 4 | // 5 | // Created by Renzo Crisostomo on 12/08/14. 6 | // Copyright (c) 2014 Renzo Crisóstomo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CityViewController: UITableViewController { 12 | 13 | var city: City! 14 | @IBOutlet weak var temperatureLabel: UILabel! 15 | @IBOutlet weak var pressureLabel: UILabel! 16 | @IBOutlet weak var humidityLabel: UILabel! 17 | 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | setupLabels() 21 | } 22 | 23 | override func didReceiveMemoryWarning() { 24 | super.didReceiveMemoryWarning() 25 | } 26 | 27 | func setupLabels() { 28 | navigationItem.title = city.name 29 | temperatureLabel.text = String(format: "%.2f °K", city.temperature) 30 | pressureLabel.text = String(format: "%.2f hpa", city.pressure) 31 | humidityLabel.text = String(format: "%.2f %%", city.humidity) 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /WeatherApp/Helpers/DatabaseHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DatabaseHelper.swift 3 | // WeatherApp 4 | // 5 | // Created by Renzo Crisostomo on 14/08/14. 6 | // Copyright (c) 2014 Renzo Crisóstomo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Realm 11 | 12 | class DatabaseHelper { 13 | 14 | func storeCities(cities: [City]) { 15 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 16 | let realm = RLMRealm.defaultRealm() 17 | let allCities = City.allObjects() 18 | realm.beginWriteTransaction() 19 | if allCities.count > 0 { 20 | realm.deleteObjects(allCities) 21 | } 22 | for city in cities { 23 | City.createInDefaultRealmWithObject(["name": city.name, "temperature": city.temperature, "pressure": city.pressure, "humidity": city.humidity]) 24 | } 25 | realm.commitWriteTransaction() 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /WeatherApp/Helpers/NetworkingHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkingHelper.swift 3 | // WeatherApp 4 | // 5 | // Created by Renzo Crisostomo on 12/08/14. 6 | // Copyright (c) 2014 Renzo Crisóstomo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class NetworkingHelper { 12 | 13 | let URL = "http://api.openweathermap.org/data/2.5/find" 14 | let translatorHelper = TranslatorHelper() 15 | 16 | func citiesWithUserLatitude(userLatitude: Double, userLongitude: Double, callback: ([City]?, NSError?)->()) { 17 | let params = ["lat": userLatitude, "lon": userLongitude, "cnt": 100.0] 18 | Alamofire.request(Alamofire.Method.GET, URL, parameters: params, encoding: Alamofire.ParameterEncoding.URL).response { (request, response, data, error) -> Void in 19 | let cities = self.translatorHelper.translateCitiesFromJSON(data) 20 | callback(cities, error) 21 | } 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /WeatherApp/Helpers/TranslatorHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TranslatorHelper.swift 3 | // WeatherApp 4 | // 5 | // Created by Renzo Crisostomo on 12/08/14. 6 | // Copyright (c) 2014 Renzo Crisóstomo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class TranslatorHelper { 12 | 13 | func translateCitiesFromJSON(data: AnyObject?) -> [City]? { 14 | if let unwrappedData = data as? NSData { 15 | let json = JSONValue(unwrappedData) 16 | if let jsonCities = json["list"].array { 17 | var cities = [City]() 18 | for jsonCity in jsonCities { 19 | let city = City() 20 | city.name = jsonCity["name"].string! 21 | city.temperature = jsonCity["main"]["temp"].double! 22 | city.pressure = jsonCity["main"]["pressure"].double! 23 | city.humidity = jsonCity["main"]["humidity"].double! 24 | cities.append(city) 25 | } 26 | return cities 27 | } 28 | } 29 | return nil 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /WeatherApp/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" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /WeatherApp/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /WeatherApp/Models/City.swift: -------------------------------------------------------------------------------- 1 | // 2 | // City.swift 3 | // WeatherApp 4 | // 5 | // Created by Renzo Crisostomo on 12/08/14. 6 | // Copyright (c) 2014 Renzo Crisóstomo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Realm 11 | 12 | class City: RLMObject { 13 | 14 | dynamic var name = "" 15 | dynamic var temperature = 0.0 16 | dynamic var pressure = 0.0 17 | dynamic var humidity = 0.0 18 | 19 | } -------------------------------------------------------------------------------- /WeatherApp/Supporting/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.ruenzuo.$(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 | NSLocationWhenInUseUsageDescription 26 | WeatherApp needs your location to retrieve data. 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /WeatherApp/Views/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 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 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 87 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 107 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | --------------------------------------------------------------------------------