├── ReadMe.md ├── Sample-UISearchController.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── Sample-UISearchController.xcscheme ├── Sample-UISearchController ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ └── Main.storyboard ├── DetailViewController.h ├── DetailViewController.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── LaunchImage.launchimage │ │ └── Contents.json │ ├── collection-tab.imageset │ │ ├── Contents.json │ │ ├── collection-tab@2x.png │ │ └── collection-tab@3x.png │ ├── filter-tab.imageset │ │ ├── Contents.json │ │ ├── filter-tab@2x.png │ │ └── filter-tab@3x.png │ └── table-tab.imageset │ │ ├── Contents.json │ │ ├── table-tab@2x.png │ │ └── table-tab@3x.png ├── Info.plist ├── MasterViewController_CollectionResults.h ├── MasterViewController_CollectionResults.m ├── MasterViewController_FilterResults.h ├── MasterViewController_FilterResults.m ├── MasterViewController_TableResults.h ├── MasterViewController_TableResults.m ├── Product.h ├── Product.m ├── SearchResultCollectionViewCell.h ├── SearchResultCollectionViewCell.m ├── SearchResultsCollectionViewController.h ├── SearchResultsCollectionViewController.m ├── SearchResultsTableViewController.h ├── SearchResultsTableViewController.m └── main.m └── Sample-UISearchControllerTests ├── Info.plist └── Sample_UISearchControllerTests.m /ReadMe.md: -------------------------------------------------------------------------------- 1 | Sample-UISearchController Read Me 2 | ================================= 3 | 4 | This example demonstrates the use of the UISearchController class, introduced in iOS 8. 5 | 6 | The project is based on the 'TableSearch' sample code from Apple. The original example used UISearchDisplayController which is deprecated in iOS 8. 7 | 8 | Each tab uses a UISearchController to display search results in a different way: 9 | - In a table view, very similar to using UISearchDisplayController 10 | 11 | - In a collection view 12 | 13 | - In place, essentially filtering the original table view 14 | 15 | **Known Issues** 16 | 17 | - The TableSearch sample project used a UISearchBar and UISearchDisplayController, configured in the storyboard. It does not appear that UISearchController can be configured in Interface Builder at the moment. Therefore, it is created and configured in code in each example. rdar://17563885 18 | 19 | - The search results controller of the UISearchController does not seem to receive all of the appropriate view controller method calls. rdar://17566947 20 | 21 | - The UISearchBar returned by UISearchController has a size of 0 x 0. The height needs to be set manually, otherwise the search bar will not be visible. Note this is when using the search bar without scope buttons. rdar://17315477 22 | 23 | *Version 2.0* 24 | *November 9, 2014* 25 | 26 | Updated for Xcode 6.1, iOS 8.1 SDK. 27 | 28 | Added a tab controller, to show three different UISearchController examples. 29 | 30 | 31 | *Version 1.0* 32 | *July 5, 2014* 33 | 34 | This project was created with Xcode 6, Beta 2. 35 | 36 | The initial version is essentially the original sample project, redone from scratch as an iOS 8 project, with as few changes in implementation as possible from the original sample project. 37 | 38 | *Version 1.0 Notes:* 39 | - There is a build warning that the scrollable content size of the table view has ambiguous constraints. Choosing to 'Add Missing Constraints' in Interface Builder has no effect, and so this warning remains. 40 | 41 | 42 | -------------------------------------------------------------------------------- /Sample-UISearchController.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 530D5EFD1967816C009E7D8D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D5EFC1967816C009E7D8D /* main.m */; }; 11 | 530D5F001967816C009E7D8D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D5EFF1967816C009E7D8D /* AppDelegate.m */; }; 12 | 530D5F031967816C009E7D8D /* MasterViewController_CollectionResults.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D5F021967816C009E7D8D /* MasterViewController_CollectionResults.m */; }; 13 | 530D5F061967816C009E7D8D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 530D5F041967816C009E7D8D /* Main.storyboard */; }; 14 | 530D5F081967816C009E7D8D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 530D5F071967816C009E7D8D /* Images.xcassets */; }; 15 | 530D5F141967816C009E7D8D /* Sample_UISearchControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D5F131967816C009E7D8D /* Sample_UISearchControllerTests.m */; }; 16 | 530D5F1F1967838F009E7D8D /* Product.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D5F1E1967838F009E7D8D /* Product.m */; }; 17 | 530D5F2219678D38009E7D8D /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D5F2119678D38009E7D8D /* DetailViewController.m */; }; 18 | 536652E619CDF67500AF3B76 /* SearchResultsCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 536652E319CDF67500AF3B76 /* SearchResultsCollectionViewController.m */; }; 19 | 536652E719CDF67500AF3B76 /* SearchResultCollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 536652E519CDF67500AF3B76 /* SearchResultCollectionViewCell.m */; }; 20 | 536652EB19CDF73400AF3B76 /* MasterViewController_TableResults.m in Sources */ = {isa = PBXBuildFile; fileRef = 536652EA19CDF73400AF3B76 /* MasterViewController_TableResults.m */; }; 21 | 536652EF19CDF9B600AF3B76 /* SearchResultsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 536652EE19CDF9B600AF3B76 /* SearchResultsTableViewController.m */; }; 22 | 536652F519CE005000AF3B76 /* MasterViewController_FilterResults.m in Sources */ = {isa = PBXBuildFile; fileRef = 536652F419CE005000AF3B76 /* MasterViewController_FilterResults.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 530D5F0E1967816C009E7D8D /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 530D5EEF1967816C009E7D8D /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = 530D5EF61967816C009E7D8D; 31 | remoteInfo = "Sample-UISearchController"; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 530D5EF71967816C009E7D8D /* Sample-UISearchController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Sample-UISearchController.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 530D5EFB1967816C009E7D8D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 530D5EFC1967816C009E7D8D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 39 | 530D5EFE1967816C009E7D8D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 40 | 530D5EFF1967816C009E7D8D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 41 | 530D5F011967816C009E7D8D /* MasterViewController_CollectionResults.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MasterViewController_CollectionResults.h; sourceTree = ""; }; 42 | 530D5F021967816C009E7D8D /* MasterViewController_CollectionResults.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MasterViewController_CollectionResults.m; sourceTree = ""; }; 43 | 530D5F051967816C009E7D8D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | 530D5F071967816C009E7D8D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 45 | 530D5F0D1967816C009E7D8D /* Sample-UISearchControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Sample-UISearchControllerTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 530D5F121967816C009E7D8D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | 530D5F131967816C009E7D8D /* Sample_UISearchControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Sample_UISearchControllerTests.m; sourceTree = ""; }; 48 | 530D5F1D1967838F009E7D8D /* Product.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Product.h; sourceTree = ""; }; 49 | 530D5F1E1967838F009E7D8D /* Product.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Product.m; sourceTree = ""; }; 50 | 530D5F2019678D38009E7D8D /* DetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetailViewController.h; sourceTree = ""; }; 51 | 530D5F2119678D38009E7D8D /* DetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DetailViewController.m; sourceTree = ""; }; 52 | 534E54F819688809006FC505 /* ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = ""; }; 53 | 536652E219CDF67500AF3B76 /* SearchResultsCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResultsCollectionViewController.h; sourceTree = ""; }; 54 | 536652E319CDF67500AF3B76 /* SearchResultsCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResultsCollectionViewController.m; sourceTree = ""; }; 55 | 536652E419CDF67500AF3B76 /* SearchResultCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResultCollectionViewCell.h; sourceTree = ""; }; 56 | 536652E519CDF67500AF3B76 /* SearchResultCollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResultCollectionViewCell.m; sourceTree = ""; }; 57 | 536652E919CDF73400AF3B76 /* MasterViewController_TableResults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MasterViewController_TableResults.h; sourceTree = ""; }; 58 | 536652EA19CDF73400AF3B76 /* MasterViewController_TableResults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MasterViewController_TableResults.m; sourceTree = ""; }; 59 | 536652ED19CDF9B600AF3B76 /* SearchResultsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchResultsTableViewController.h; sourceTree = ""; }; 60 | 536652EE19CDF9B600AF3B76 /* SearchResultsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchResultsTableViewController.m; sourceTree = ""; }; 61 | 536652F319CE005000AF3B76 /* MasterViewController_FilterResults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MasterViewController_FilterResults.h; sourceTree = ""; }; 62 | 536652F419CE005000AF3B76 /* MasterViewController_FilterResults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MasterViewController_FilterResults.m; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 530D5EF41967816C009E7D8D /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | 530D5F0A1967816C009E7D8D /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | /* End PBXFrameworksBuildPhase section */ 81 | 82 | /* Begin PBXGroup section */ 83 | 530D5EEE1967816C009E7D8D = { 84 | isa = PBXGroup; 85 | children = ( 86 | 530D5EF91967816C009E7D8D /* Sample-UISearchController */, 87 | 530D5F101967816C009E7D8D /* Sample-UISearchControllerTests */, 88 | 534E54F819688809006FC505 /* ReadMe.md */, 89 | 530D5EF81967816C009E7D8D /* Products */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | 530D5EF81967816C009E7D8D /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 530D5EF71967816C009E7D8D /* Sample-UISearchController.app */, 97 | 530D5F0D1967816C009E7D8D /* Sample-UISearchControllerTests.xctest */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 530D5EF91967816C009E7D8D /* Sample-UISearchController */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 530D5EFE1967816C009E7D8D /* AppDelegate.h */, 106 | 530D5EFF1967816C009E7D8D /* AppDelegate.m */, 107 | 530D5F2019678D38009E7D8D /* DetailViewController.h */, 108 | 530D5F2119678D38009E7D8D /* DetailViewController.m */, 109 | 530D5F1D1967838F009E7D8D /* Product.h */, 110 | 530D5F1E1967838F009E7D8D /* Product.m */, 111 | 536652EC19CDF99200AF3B76 /* TableViewResults */, 112 | 536652E819CDF67C00AF3B76 /* CollectionViewResults */, 113 | 536652F619CE00FC00AF3B76 /* FilterResults */, 114 | 530D5F041967816C009E7D8D /* Main.storyboard */, 115 | 530D5F071967816C009E7D8D /* Images.xcassets */, 116 | 530D5EFA1967816C009E7D8D /* Supporting Files */, 117 | ); 118 | path = "Sample-UISearchController"; 119 | sourceTree = ""; 120 | }; 121 | 530D5EFA1967816C009E7D8D /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 530D5EFB1967816C009E7D8D /* Info.plist */, 125 | 530D5EFC1967816C009E7D8D /* main.m */, 126 | ); 127 | name = "Supporting Files"; 128 | sourceTree = ""; 129 | }; 130 | 530D5F101967816C009E7D8D /* Sample-UISearchControllerTests */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 530D5F131967816C009E7D8D /* Sample_UISearchControllerTests.m */, 134 | 530D5F111967816C009E7D8D /* Supporting Files */, 135 | ); 136 | path = "Sample-UISearchControllerTests"; 137 | sourceTree = ""; 138 | }; 139 | 530D5F111967816C009E7D8D /* Supporting Files */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 530D5F121967816C009E7D8D /* Info.plist */, 143 | ); 144 | name = "Supporting Files"; 145 | sourceTree = ""; 146 | }; 147 | 536652E819CDF67C00AF3B76 /* CollectionViewResults */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 530D5F011967816C009E7D8D /* MasterViewController_CollectionResults.h */, 151 | 530D5F021967816C009E7D8D /* MasterViewController_CollectionResults.m */, 152 | 536652E219CDF67500AF3B76 /* SearchResultsCollectionViewController.h */, 153 | 536652E319CDF67500AF3B76 /* SearchResultsCollectionViewController.m */, 154 | 536652E419CDF67500AF3B76 /* SearchResultCollectionViewCell.h */, 155 | 536652E519CDF67500AF3B76 /* SearchResultCollectionViewCell.m */, 156 | ); 157 | name = CollectionViewResults; 158 | sourceTree = ""; 159 | }; 160 | 536652EC19CDF99200AF3B76 /* TableViewResults */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 536652E919CDF73400AF3B76 /* MasterViewController_TableResults.h */, 164 | 536652EA19CDF73400AF3B76 /* MasterViewController_TableResults.m */, 165 | 536652ED19CDF9B600AF3B76 /* SearchResultsTableViewController.h */, 166 | 536652EE19CDF9B600AF3B76 /* SearchResultsTableViewController.m */, 167 | ); 168 | name = TableViewResults; 169 | sourceTree = ""; 170 | }; 171 | 536652F619CE00FC00AF3B76 /* FilterResults */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | 536652F319CE005000AF3B76 /* MasterViewController_FilterResults.h */, 175 | 536652F419CE005000AF3B76 /* MasterViewController_FilterResults.m */, 176 | ); 177 | name = FilterResults; 178 | sourceTree = ""; 179 | }; 180 | /* End PBXGroup section */ 181 | 182 | /* Begin PBXNativeTarget section */ 183 | 530D5EF61967816C009E7D8D /* Sample-UISearchController */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 530D5F171967816C009E7D8D /* Build configuration list for PBXNativeTarget "Sample-UISearchController" */; 186 | buildPhases = ( 187 | 530D5EF31967816C009E7D8D /* Sources */, 188 | 530D5EF41967816C009E7D8D /* Frameworks */, 189 | 530D5EF51967816C009E7D8D /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | ); 195 | name = "Sample-UISearchController"; 196 | productName = "Sample-UISearchController"; 197 | productReference = 530D5EF71967816C009E7D8D /* Sample-UISearchController.app */; 198 | productType = "com.apple.product-type.application"; 199 | }; 200 | 530D5F0C1967816C009E7D8D /* Sample-UISearchControllerTests */ = { 201 | isa = PBXNativeTarget; 202 | buildConfigurationList = 530D5F1A1967816C009E7D8D /* Build configuration list for PBXNativeTarget "Sample-UISearchControllerTests" */; 203 | buildPhases = ( 204 | 530D5F091967816C009E7D8D /* Sources */, 205 | 530D5F0A1967816C009E7D8D /* Frameworks */, 206 | 530D5F0B1967816C009E7D8D /* Resources */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | 530D5F0F1967816C009E7D8D /* PBXTargetDependency */, 212 | ); 213 | name = "Sample-UISearchControllerTests"; 214 | productName = "Sample-UISearchControllerTests"; 215 | productReference = 530D5F0D1967816C009E7D8D /* Sample-UISearchControllerTests.xctest */; 216 | productType = "com.apple.product-type.bundle.unit-test"; 217 | }; 218 | /* End PBXNativeTarget section */ 219 | 220 | /* Begin PBXProject section */ 221 | 530D5EEF1967816C009E7D8D /* Project object */ = { 222 | isa = PBXProject; 223 | attributes = { 224 | LastUpgradeCheck = 0600; 225 | ORGANIZATIONNAME = "Tapas Software"; 226 | TargetAttributes = { 227 | 530D5EF61967816C009E7D8D = { 228 | CreatedOnToolsVersion = 6.0; 229 | }; 230 | 530D5F0C1967816C009E7D8D = { 231 | CreatedOnToolsVersion = 6.0; 232 | TestTargetID = 530D5EF61967816C009E7D8D; 233 | }; 234 | }; 235 | }; 236 | buildConfigurationList = 530D5EF21967816C009E7D8D /* Build configuration list for PBXProject "Sample-UISearchController" */; 237 | compatibilityVersion = "Xcode 3.2"; 238 | developmentRegion = English; 239 | hasScannedForEncodings = 0; 240 | knownRegions = ( 241 | en, 242 | Base, 243 | ); 244 | mainGroup = 530D5EEE1967816C009E7D8D; 245 | productRefGroup = 530D5EF81967816C009E7D8D /* Products */; 246 | projectDirPath = ""; 247 | projectRoot = ""; 248 | targets = ( 249 | 530D5EF61967816C009E7D8D /* Sample-UISearchController */, 250 | 530D5F0C1967816C009E7D8D /* Sample-UISearchControllerTests */, 251 | ); 252 | }; 253 | /* End PBXProject section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | 530D5EF51967816C009E7D8D /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 530D5F061967816C009E7D8D /* Main.storyboard in Resources */, 261 | 530D5F081967816C009E7D8D /* Images.xcassets in Resources */, 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | }; 265 | 530D5F0B1967816C009E7D8D /* Resources */ = { 266 | isa = PBXResourcesBuildPhase; 267 | buildActionMask = 2147483647; 268 | files = ( 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | /* End PBXResourcesBuildPhase section */ 273 | 274 | /* Begin PBXSourcesBuildPhase section */ 275 | 530D5EF31967816C009E7D8D /* Sources */ = { 276 | isa = PBXSourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | 530D5F031967816C009E7D8D /* MasterViewController_CollectionResults.m in Sources */, 280 | 536652E619CDF67500AF3B76 /* SearchResultsCollectionViewController.m in Sources */, 281 | 530D5F001967816C009E7D8D /* AppDelegate.m in Sources */, 282 | 530D5F2219678D38009E7D8D /* DetailViewController.m in Sources */, 283 | 536652F519CE005000AF3B76 /* MasterViewController_FilterResults.m in Sources */, 284 | 536652EF19CDF9B600AF3B76 /* SearchResultsTableViewController.m in Sources */, 285 | 530D5EFD1967816C009E7D8D /* main.m in Sources */, 286 | 536652E719CDF67500AF3B76 /* SearchResultCollectionViewCell.m in Sources */, 287 | 536652EB19CDF73400AF3B76 /* MasterViewController_TableResults.m in Sources */, 288 | 530D5F1F1967838F009E7D8D /* Product.m in Sources */, 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | }; 292 | 530D5F091967816C009E7D8D /* Sources */ = { 293 | isa = PBXSourcesBuildPhase; 294 | buildActionMask = 2147483647; 295 | files = ( 296 | 530D5F141967816C009E7D8D /* Sample_UISearchControllerTests.m in Sources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | /* End PBXSourcesBuildPhase section */ 301 | 302 | /* Begin PBXTargetDependency section */ 303 | 530D5F0F1967816C009E7D8D /* PBXTargetDependency */ = { 304 | isa = PBXTargetDependency; 305 | target = 530D5EF61967816C009E7D8D /* Sample-UISearchController */; 306 | targetProxy = 530D5F0E1967816C009E7D8D /* PBXContainerItemProxy */; 307 | }; 308 | /* End PBXTargetDependency section */ 309 | 310 | /* Begin PBXVariantGroup section */ 311 | 530D5F041967816C009E7D8D /* Main.storyboard */ = { 312 | isa = PBXVariantGroup; 313 | children = ( 314 | 530D5F051967816C009E7D8D /* Base */, 315 | ); 316 | name = Main.storyboard; 317 | sourceTree = ""; 318 | }; 319 | /* End PBXVariantGroup section */ 320 | 321 | /* Begin XCBuildConfiguration section */ 322 | 530D5F151967816C009E7D8D /* Debug */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ALWAYS_SEARCH_USER_PATHS = NO; 326 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 327 | CLANG_CXX_LIBRARY = "libc++"; 328 | CLANG_ENABLE_MODULES = YES; 329 | CLANG_ENABLE_OBJC_ARC = YES; 330 | CLANG_WARN_BOOL_CONVERSION = YES; 331 | CLANG_WARN_CONSTANT_CONVERSION = YES; 332 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 333 | CLANG_WARN_EMPTY_BODY = YES; 334 | CLANG_WARN_ENUM_CONVERSION = YES; 335 | CLANG_WARN_INT_CONVERSION = YES; 336 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 337 | CLANG_WARN_UNREACHABLE_CODE = YES; 338 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 339 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 340 | COPY_PHASE_STRIP = NO; 341 | ENABLE_STRICT_OBJC_MSGSEND = YES; 342 | GCC_C_LANGUAGE_STANDARD = gnu99; 343 | GCC_DYNAMIC_NO_PIC = NO; 344 | GCC_OPTIMIZATION_LEVEL = 0; 345 | GCC_PREPROCESSOR_DEFINITIONS = ( 346 | "DEBUG=1", 347 | "$(inherited)", 348 | ); 349 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 350 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 351 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 352 | GCC_WARN_UNDECLARED_SELECTOR = YES; 353 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 354 | GCC_WARN_UNUSED_FUNCTION = YES; 355 | GCC_WARN_UNUSED_VARIABLE = YES; 356 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 357 | METAL_ENABLE_DEBUG_INFO = YES; 358 | ONLY_ACTIVE_ARCH = YES; 359 | SDKROOT = iphoneos; 360 | }; 361 | name = Debug; 362 | }; 363 | 530D5F161967816C009E7D8D /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ALWAYS_SEARCH_USER_PATHS = NO; 367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 368 | CLANG_CXX_LIBRARY = "libc++"; 369 | CLANG_ENABLE_MODULES = YES; 370 | CLANG_ENABLE_OBJC_ARC = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_EMPTY_BODY = YES; 375 | CLANG_WARN_ENUM_CONVERSION = YES; 376 | CLANG_WARN_INT_CONVERSION = YES; 377 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 378 | CLANG_WARN_UNREACHABLE_CODE = YES; 379 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 380 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 381 | COPY_PHASE_STRIP = YES; 382 | ENABLE_NS_ASSERTIONS = NO; 383 | ENABLE_STRICT_OBJC_MSGSEND = YES; 384 | GCC_C_LANGUAGE_STANDARD = gnu99; 385 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 386 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 387 | GCC_WARN_UNDECLARED_SELECTOR = YES; 388 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 389 | GCC_WARN_UNUSED_FUNCTION = YES; 390 | GCC_WARN_UNUSED_VARIABLE = YES; 391 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 392 | METAL_ENABLE_DEBUG_INFO = NO; 393 | SDKROOT = iphoneos; 394 | VALIDATE_PRODUCT = YES; 395 | }; 396 | name = Release; 397 | }; 398 | 530D5F181967816C009E7D8D /* Debug */ = { 399 | isa = XCBuildConfiguration; 400 | buildSettings = { 401 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 402 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 403 | INFOPLIST_FILE = "Sample-UISearchController/Info.plist"; 404 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 405 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 406 | PRODUCT_NAME = "$(TARGET_NAME)"; 407 | TARGETED_DEVICE_FAMILY = 1; 408 | }; 409 | name = Debug; 410 | }; 411 | 530D5F191967816C009E7D8D /* Release */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 415 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 416 | INFOPLIST_FILE = "Sample-UISearchController/Info.plist"; 417 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 418 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | TARGETED_DEVICE_FAMILY = 1; 421 | }; 422 | name = Release; 423 | }; 424 | 530D5F1B1967816C009E7D8D /* Debug */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Sample-UISearchController.app/Sample-UISearchController"; 428 | FRAMEWORK_SEARCH_PATHS = ( 429 | "$(SDKROOT)/Developer/Library/Frameworks", 430 | "$(inherited)", 431 | ); 432 | GCC_PREPROCESSOR_DEFINITIONS = ( 433 | "DEBUG=1", 434 | "$(inherited)", 435 | ); 436 | INFOPLIST_FILE = "Sample-UISearchControllerTests/Info.plist"; 437 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 438 | METAL_ENABLE_DEBUG_INFO = YES; 439 | PRODUCT_NAME = "$(TARGET_NAME)"; 440 | TEST_HOST = "$(BUNDLE_LOADER)"; 441 | }; 442 | name = Debug; 443 | }; 444 | 530D5F1C1967816C009E7D8D /* Release */ = { 445 | isa = XCBuildConfiguration; 446 | buildSettings = { 447 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Sample-UISearchController.app/Sample-UISearchController"; 448 | FRAMEWORK_SEARCH_PATHS = ( 449 | "$(SDKROOT)/Developer/Library/Frameworks", 450 | "$(inherited)", 451 | ); 452 | INFOPLIST_FILE = "Sample-UISearchControllerTests/Info.plist"; 453 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 454 | METAL_ENABLE_DEBUG_INFO = NO; 455 | PRODUCT_NAME = "$(TARGET_NAME)"; 456 | TEST_HOST = "$(BUNDLE_LOADER)"; 457 | }; 458 | name = Release; 459 | }; 460 | /* End XCBuildConfiguration section */ 461 | 462 | /* Begin XCConfigurationList section */ 463 | 530D5EF21967816C009E7D8D /* Build configuration list for PBXProject "Sample-UISearchController" */ = { 464 | isa = XCConfigurationList; 465 | buildConfigurations = ( 466 | 530D5F151967816C009E7D8D /* Debug */, 467 | 530D5F161967816C009E7D8D /* Release */, 468 | ); 469 | defaultConfigurationIsVisible = 0; 470 | defaultConfigurationName = Release; 471 | }; 472 | 530D5F171967816C009E7D8D /* Build configuration list for PBXNativeTarget "Sample-UISearchController" */ = { 473 | isa = XCConfigurationList; 474 | buildConfigurations = ( 475 | 530D5F181967816C009E7D8D /* Debug */, 476 | 530D5F191967816C009E7D8D /* Release */, 477 | ); 478 | defaultConfigurationIsVisible = 0; 479 | defaultConfigurationName = Release; 480 | }; 481 | 530D5F1A1967816C009E7D8D /* Build configuration list for PBXNativeTarget "Sample-UISearchControllerTests" */ = { 482 | isa = XCConfigurationList; 483 | buildConfigurations = ( 484 | 530D5F1B1967816C009E7D8D /* Debug */, 485 | 530D5F1C1967816C009E7D8D /* Release */, 486 | ); 487 | defaultConfigurationIsVisible = 0; 488 | defaultConfigurationName = Release; 489 | }; 490 | /* End XCConfigurationList section */ 491 | }; 492 | rootObject = 530D5EEF1967816C009E7D8D /* Project object */; 493 | } 494 | -------------------------------------------------------------------------------- /Sample-UISearchController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample-UISearchController.xcodeproj/xcshareddata/xcschemes/Sample-UISearchController.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Sample-UISearchController/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TPSAppDelegate.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /Sample-UISearchController/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TPSAppDelegate.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import "AppDelegate.h" 12 | 13 | @interface AppDelegate () 14 | @end 15 | 16 | @implementation AppDelegate 17 | @end 18 | -------------------------------------------------------------------------------- /Sample-UISearchController/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 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 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 | 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 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | -------------------------------------------------------------------------------- /Sample-UISearchController/DetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TPSDetailViewController.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import 12 | 13 | @class Product; 14 | 15 | @interface DetailViewController : UIViewController 16 | 17 | @property (nonatomic, strong) Product *product; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Sample-UISearchController/DetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TPSDetailViewController.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import "DetailViewController.h" 12 | #import "Product.h" 13 | 14 | @interface DetailViewController () 15 | @end 16 | 17 | @implementation DetailViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.title = self.product.name; 22 | } 23 | 24 | @end -------------------------------------------------------------------------------- /Sample-UISearchController/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 | "idiom" : "iphone", 20 | "size" : "60x60", 21 | "scale" : "3x" 22 | } 23 | ], 24 | "info" : { 25 | "version" : 1, 26 | "author" : "xcode" 27 | } 28 | } -------------------------------------------------------------------------------- /Sample-UISearchController/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 | } -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/collection-tab.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "collection-tab@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "collection-tab@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/collection-tab.imageset/collection-tab@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dempseyatgithub/Sample-UISearchController/529affc818020d11289ce6422515bd58d0c2c3a4/Sample-UISearchController/Images.xcassets/collection-tab.imageset/collection-tab@2x.png -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/collection-tab.imageset/collection-tab@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dempseyatgithub/Sample-UISearchController/529affc818020d11289ce6422515bd58d0c2c3a4/Sample-UISearchController/Images.xcassets/collection-tab.imageset/collection-tab@3x.png -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/filter-tab.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "filter-tab@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x", 15 | "filename" : "filter-tab@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/filter-tab.imageset/filter-tab@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dempseyatgithub/Sample-UISearchController/529affc818020d11289ce6422515bd58d0c2c3a4/Sample-UISearchController/Images.xcassets/filter-tab.imageset/filter-tab@2x.png -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/filter-tab.imageset/filter-tab@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dempseyatgithub/Sample-UISearchController/529affc818020d11289ce6422515bd58d0c2c3a4/Sample-UISearchController/Images.xcassets/filter-tab.imageset/filter-tab@3x.png -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/table-tab.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "iphone", 9 | "scale" : "2x", 10 | "filename" : "table-tab@2x.png" 11 | }, 12 | { 13 | "idiom" : "iphone", 14 | "scale" : "3x", 15 | "filename" : "table-tab@3x.png" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/table-tab.imageset/table-tab@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dempseyatgithub/Sample-UISearchController/529affc818020d11289ce6422515bd58d0c2c3a4/Sample-UISearchController/Images.xcassets/table-tab.imageset/table-tab@2x.png -------------------------------------------------------------------------------- /Sample-UISearchController/Images.xcassets/table-tab.imageset/table-tab@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dempseyatgithub/Sample-UISearchController/529affc818020d11289ce6422515bd58d0c2c3a4/Sample-UISearchController/Images.xcassets/table-tab.imageset/table-tab@3x.png -------------------------------------------------------------------------------- /Sample-UISearchController/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | net.tapas-software.${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 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Sample-UISearchController/MasterViewController_CollectionResults.h: -------------------------------------------------------------------------------- 1 | // 2 | // TPSMasterViewController.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import 12 | 13 | @interface MasterViewController_CollectionResults : UITableViewController 14 | 15 | @property (nonatomic, strong) NSArray *products; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /Sample-UISearchController/MasterViewController_CollectionResults.m: -------------------------------------------------------------------------------- 1 | // 2 | // TPSMasterViewController.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import "MasterViewController_CollectionResults.h" 12 | #import "SearchResultsCollectionViewController.h" 13 | #import "DetailViewController.h" 14 | #import "Product.h" 15 | 16 | #define ENABLE_SCOPE_BUTTONS 1 17 | 18 | 19 | @interface MasterViewController_CollectionResults () 20 | 21 | @property (nonatomic, strong) UISearchController *searchController; 22 | @property (nonatomic, strong) NSMutableArray *searchResults; // Filtered search results 23 | 24 | @end 25 | 26 | #pragma mark - 27 | 28 | @implementation MasterViewController_CollectionResults 29 | 30 | - (void)viewDidLoad { 31 | 32 | [super viewDidLoad]; 33 | 34 | self.products = [Product allProducts]; 35 | 36 | // Create a mutable array to contain products for the search results table. 37 | self.searchResults = [NSMutableArray arrayWithCapacity:[self.products count]]; 38 | 39 | // The collection view controller is in a nav controller, and so the containing nav controller is the 'search results controller' 40 | UINavigationController *searchResultsController = [[self storyboard] instantiateViewControllerWithIdentifier:@"CollectionSearchResultsNavController"]; 41 | 42 | self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController]; 43 | 44 | self.searchController.searchResultsUpdater = self; 45 | 46 | self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0); 47 | 48 | self.tableView.tableHeaderView = self.searchController.searchBar; 49 | 50 | self.definesPresentationContext = YES; 51 | 52 | } 53 | 54 | -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 55 | 56 | if ([segue.identifier isEqualToString:@"pushDetailView"]) { 57 | 58 | // Sender is the table view cell. 59 | NSArray *sourceArray; 60 | NSIndexPath* indexPath = [self.tableView indexPathForCell:(UITableViewCell *)sender]; 61 | sourceArray = self.products; 62 | 63 | UIViewController *destinationController = segue.destinationViewController; 64 | Product *product = sourceArray[indexPath.row]; 65 | ((DetailViewController *)destinationController).product = product; 66 | } 67 | } 68 | 69 | 70 | #pragma mark - UITableViewDataSource 71 | 72 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 73 | 74 | return [self.products count]; 75 | } 76 | 77 | 78 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 79 | 80 | UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"ProductCell" forIndexPath:indexPath]; 81 | 82 | Product *product = [self.products objectAtIndex:indexPath.row]; 83 | 84 | cell.textLabel.text = product.name; 85 | return cell; 86 | } 87 | 88 | 89 | #pragma mark - UISearchResultsUpdating 90 | 91 | -(void)updateSearchResultsForSearchController:(UISearchController *)searchController { 92 | 93 | NSString *searchString = [self.searchController.searchBar text]; 94 | 95 | NSString *scope = nil; 96 | 97 | NSInteger selectedScopeButtonIndex = [self.searchController.searchBar selectedScopeButtonIndex]; 98 | if (selectedScopeButtonIndex > 0) { 99 | scope = [[Product deviceTypeNames] objectAtIndex:(selectedScopeButtonIndex - 1)]; 100 | } 101 | 102 | [self updateFilteredContentForProductName:searchString type:scope]; 103 | 104 | if (self.searchController.searchResultsController) { 105 | UINavigationController *navController = (UINavigationController *)self.searchController.searchResultsController; 106 | 107 | SearchResultsCollectionViewController *vc = (SearchResultsCollectionViewController *)navController.topViewController; 108 | vc.searchResults = self.searchResults; 109 | [vc.collectionView reloadData]; 110 | } 111 | 112 | } 113 | 114 | 115 | #pragma mark - Content Filtering 116 | 117 | - (void)updateFilteredContentForProductName:(NSString *)productName type:(NSString *)typeName { 118 | 119 | // Update the filtered array based on the search text and scope. 120 | if ((productName == nil) || [productName length] == 0) { 121 | // If there is no search string and the scope is "All". 122 | if (typeName == nil) { 123 | self.searchResults = [self.products mutableCopy]; 124 | } else { 125 | // If there is no search string and the scope is chosen. 126 | NSMutableArray *searchResults = [[NSMutableArray alloc] init]; 127 | for (Product *product in self.products) { 128 | if ([product.type isEqualToString:typeName]) { 129 | [searchResults addObject:product]; 130 | } 131 | } 132 | self.searchResults = searchResults; 133 | } 134 | return; 135 | } 136 | 137 | [self.searchResults removeAllObjects]; // First clear the filtered array. 138 | 139 | /* Search the main list for products whose type matches the scope (if selected) and whose name matches searchText; add items that match to the filtered array. 140 | */ 141 | for (Product *product in self.products) { 142 | if ((typeName == nil) || [product.type isEqualToString:typeName]) { 143 | NSUInteger searchOptions = NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch; 144 | NSRange productNameRange = NSMakeRange(0, product.name.length); 145 | NSRange foundRange = [product.name rangeOfString:productName options:searchOptions range:productNameRange]; 146 | if (foundRange.length > 0) { 147 | [self.searchResults addObject:product]; 148 | } 149 | } 150 | } 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /Sample-UISearchController/MasterViewController_FilterResults.h: -------------------------------------------------------------------------------- 1 | // 2 | // TPSMasterViewController.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import 12 | 13 | @interface MasterViewController_FilterResults : UITableViewController 14 | 15 | @property (nonatomic, strong) NSArray *products; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /Sample-UISearchController/MasterViewController_FilterResults.m: -------------------------------------------------------------------------------- 1 | // 2 | // TPSMasterViewController.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import "MasterViewController_FilterResults.h" 12 | #import "DetailViewController.h" 13 | #import "Product.h" 14 | 15 | #define ENABLE_SCOPE_BUTTONS 1 16 | 17 | 18 | @interface MasterViewController_FilterResults () 19 | 20 | @property (nonatomic, strong) UISearchController *searchController; 21 | @property (nonatomic, strong) NSMutableArray *searchResults; // Filtered search results 22 | 23 | @end 24 | 25 | #pragma mark - 26 | 27 | @implementation MasterViewController_FilterResults 28 | 29 | - (void)viewDidLoad { 30 | 31 | [super viewDidLoad]; 32 | 33 | self.products = [Product allProducts]; 34 | 35 | // Create a mutable array to contain products for the search results table. 36 | self.searchResults = [NSMutableArray arrayWithCapacity:[self.products count]]; 37 | 38 | self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil]; 39 | 40 | self.searchController.searchResultsUpdater = self; 41 | 42 | self.searchController.dimsBackgroundDuringPresentation = NO; 43 | self.searchController.hidesNavigationBarDuringPresentation = NO; 44 | 45 | self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0); 46 | 47 | self.tableView.tableHeaderView = self.searchController.searchBar; 48 | 49 | #if ENABLE_SCOPE_BUTTONS 50 | 51 | NSMutableArray *scopeButtonTitles = [[NSMutableArray alloc] init]; 52 | [scopeButtonTitles addObject:NSLocalizedString(@"All", @"Search display controller All button.")]; 53 | 54 | for (NSString *deviceType in [Product deviceTypeNames]) 55 | { 56 | NSString *displayName = [Product displayNameForType:deviceType]; 57 | [scopeButtonTitles addObject:displayName]; 58 | } 59 | 60 | self.searchController.searchBar.scopeButtonTitles = scopeButtonTitles; 61 | self.searchController.searchBar.delegate = self; 62 | 63 | #endif 64 | 65 | self.definesPresentationContext = YES; 66 | 67 | } 68 | 69 | -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 70 | 71 | NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; 72 | 73 | NSArray *sourceArray = self.searchController.active ? self.searchResults : self.products; 74 | 75 | UIViewController *destinationController = segue.destinationViewController; 76 | Product *product = sourceArray[indexPath.row]; 77 | ((DetailViewController *)destinationController).product = product; 78 | } 79 | 80 | 81 | #pragma mark - UITableViewDataSource 82 | 83 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 84 | 85 | if (self.searchController.active) { 86 | return [self.searchResults count]; 87 | } else { 88 | return [self.products count]; 89 | } 90 | } 91 | 92 | 93 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 94 | static NSString *CellIdentifier = @"ProductCell"; 95 | 96 | // Dequeue a cell from self's table view. 97 | UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 98 | 99 | /* If the requesting table view is the search controller's table view, configure the cell using the search results array, otherwise use the product array. 100 | */ 101 | Product *product; 102 | 103 | if (self.searchController.active) { 104 | product = [self.searchResults objectAtIndex:indexPath.row]; 105 | } else { 106 | product = [self.products objectAtIndex:indexPath.row]; 107 | } 108 | 109 | cell.textLabel.text = product.name; 110 | return cell; 111 | } 112 | 113 | 114 | #pragma mark - UISearchResultsUpdating 115 | 116 | -(void)updateSearchResultsForSearchController:(UISearchController *)searchController { 117 | 118 | NSString *searchString = [self.searchController.searchBar text]; 119 | 120 | NSString *scope = nil; 121 | 122 | NSInteger selectedScopeButtonIndex = [self.searchController.searchBar selectedScopeButtonIndex]; 123 | if (selectedScopeButtonIndex > 0) { 124 | scope = [[Product deviceTypeNames] objectAtIndex:(selectedScopeButtonIndex - 1)]; 125 | } 126 | 127 | [self updateFilteredContentForProductName:searchString type:scope]; 128 | 129 | [self.tableView reloadData]; 130 | } 131 | 132 | #pragma mark - UISearchBarDelegate 133 | 134 | // Workaround for bug: -updateSearchResultsForSearchController: is not called when scope buttons change 135 | - (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope { 136 | [self updateSearchResultsForSearchController:self.searchController]; 137 | } 138 | 139 | 140 | #pragma mark - Content Filtering 141 | 142 | - (void)updateFilteredContentForProductName:(NSString *)productName type:(NSString *)typeName { 143 | 144 | // Update the filtered array based on the search text and scope. 145 | if ((productName == nil) || [productName length] == 0) { 146 | // If there is no search string and the scope is "All". 147 | if (typeName == nil) { 148 | self.searchResults = [self.products mutableCopy]; 149 | } else { 150 | // If there is no search string and the scope is chosen. 151 | NSMutableArray *searchResults = [[NSMutableArray alloc] init]; 152 | for (Product *product in self.products) { 153 | if ([product.type isEqualToString:typeName]) { 154 | [searchResults addObject:product]; 155 | } 156 | } 157 | self.searchResults = searchResults; 158 | } 159 | return; 160 | } 161 | 162 | 163 | [self.searchResults removeAllObjects]; // First clear the filtered array. 164 | 165 | /* Search the main list for products whose type matches the scope (if selected) and whose name matches searchText; add items that match to the filtered array. 166 | */ 167 | for (Product *product in self.products) { 168 | if ((typeName == nil) || [product.type isEqualToString:typeName]) { 169 | NSUInteger searchOptions = NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch; 170 | NSRange productNameRange = NSMakeRange(0, product.name.length); 171 | NSRange foundRange = [product.name rangeOfString:productName options:searchOptions range:productNameRange]; 172 | if (foundRange.length > 0) { 173 | [self.searchResults addObject:product]; 174 | } 175 | } 176 | } 177 | } 178 | 179 | @end 180 | -------------------------------------------------------------------------------- /Sample-UISearchController/MasterViewController_TableResults.h: -------------------------------------------------------------------------------- 1 | // 2 | // TPSMasterViewController.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import 12 | 13 | @interface MasterViewController_TableResults : UITableViewController 14 | 15 | @property (nonatomic, strong) NSArray *products; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /Sample-UISearchController/MasterViewController_TableResults.m: -------------------------------------------------------------------------------- 1 | // 2 | // TPSMasterViewController.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import "MasterViewController_TableResults.h" 12 | #import "DetailViewController.h" 13 | #import "SearchResultsTableViewController.h" 14 | #import "Product.h" 15 | 16 | #define ENABLE_SCOPE_BUTTONS 1 17 | 18 | 19 | @interface MasterViewController_TableResults () 20 | 21 | @property (nonatomic, strong) UISearchController *searchController; 22 | @property (nonatomic, strong) NSMutableArray *searchResults; // Filtered search results 23 | 24 | @end 25 | 26 | #pragma mark - 27 | 28 | @implementation MasterViewController_TableResults 29 | 30 | - (void)viewDidLoad { 31 | 32 | [super viewDidLoad]; 33 | 34 | self.products = [Product allProducts]; 35 | 36 | // Create a mutable array to contain products for the search results table. 37 | self.searchResults = [NSMutableArray arrayWithCapacity:[self.products count]]; 38 | 39 | // The table view controller is in a nav controller, and so the containing nav controller is the 'search results controller' 40 | UINavigationController *searchResultsController = [[self storyboard] instantiateViewControllerWithIdentifier:@"TableSearchResultsNavController"]; 41 | 42 | self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController]; 43 | 44 | self.searchController.searchResultsUpdater = self; 45 | 46 | self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0); 47 | 48 | self.tableView.tableHeaderView = self.searchController.searchBar; 49 | 50 | #if ENABLE_SCOPE_BUTTONS 51 | 52 | NSMutableArray *scopeButtonTitles = [[NSMutableArray alloc] init]; 53 | [scopeButtonTitles addObject:NSLocalizedString(@"All", @"Search display controller All button.")]; 54 | 55 | for (NSString *deviceType in [Product deviceTypeNames]) { 56 | NSString *displayName = [Product displayNameForType:deviceType]; 57 | [scopeButtonTitles addObject:displayName]; 58 | } 59 | 60 | self.searchController.searchBar.scopeButtonTitles = scopeButtonTitles; 61 | self.searchController.searchBar.delegate = self; 62 | 63 | #endif 64 | 65 | self.definesPresentationContext = YES; 66 | 67 | } 68 | 69 | -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 70 | 71 | if ([segue.identifier isEqualToString:@"pushDetailView"]) { 72 | NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; 73 | Product *product = self.products[indexPath.row]; 74 | 75 | DetailViewController *destinationController = segue.destinationViewController; 76 | destinationController.product = product; 77 | } 78 | 79 | } 80 | 81 | 82 | #pragma mark - UITableViewDataSource 83 | 84 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 85 | 86 | return [self.products count]; 87 | 88 | } 89 | 90 | 91 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 92 | static NSString *CellIdentifier = @"ProductCell"; 93 | 94 | UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 95 | 96 | Product *product = [self.products objectAtIndex:indexPath.row]; 97 | cell.textLabel.text = product.name; 98 | return cell; 99 | } 100 | 101 | 102 | #pragma mark - UISearchResultsUpdating 103 | 104 | -(void)updateSearchResultsForSearchController:(UISearchController *)searchController { 105 | 106 | NSString *searchString = [self.searchController.searchBar text]; 107 | 108 | NSString *scope = nil; 109 | 110 | NSInteger selectedScopeButtonIndex = [self.searchController.searchBar selectedScopeButtonIndex]; 111 | if (selectedScopeButtonIndex > 0) { 112 | scope = [[Product deviceTypeNames] objectAtIndex:(selectedScopeButtonIndex - 1)]; 113 | } 114 | 115 | [self updateFilteredContentForProductName:searchString type:scope]; 116 | 117 | if (self.searchController.searchResultsController) { 118 | UINavigationController *navController = (UINavigationController *)self.searchController.searchResultsController; 119 | 120 | SearchResultsTableViewController *vc = (SearchResultsTableViewController *)navController.topViewController; 121 | vc.searchResults = self.searchResults; 122 | [vc.tableView reloadData]; 123 | } 124 | 125 | } 126 | 127 | #pragma mark - UISearchBarDelegate 128 | 129 | // Workaround for bug: -updateSearchResultsForSearchController: is not called when scope buttons change 130 | - (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope { 131 | [self updateSearchResultsForSearchController:self.searchController]; 132 | } 133 | 134 | 135 | #pragma mark - Content Filtering 136 | 137 | - (void)updateFilteredContentForProductName:(NSString *)productName type:(NSString *)typeName { 138 | 139 | // Update the filtered array based on the search text and scope. 140 | if ((productName == nil) || [productName length] == 0) { 141 | // If there is no search string and the scope is "All". 142 | if (typeName == nil) { 143 | self.searchResults = [self.products mutableCopy]; 144 | } else { 145 | // If there is no search string and the scope is chosen. 146 | NSMutableArray *searchResults = [[NSMutableArray alloc] init]; 147 | for (Product *product in self.products) { 148 | if ([product.type isEqualToString:typeName]) { 149 | [searchResults addObject:product]; 150 | } 151 | } 152 | self.searchResults = searchResults; 153 | } 154 | return; 155 | } 156 | 157 | 158 | [self.searchResults removeAllObjects]; // First clear the filtered array. 159 | 160 | /* Search the main list for products whose type matches the scope (if selected) and whose name matches searchText; add items that match to the filtered array. 161 | */ 162 | for (Product *product in self.products) { 163 | if ((typeName == nil) || [product.type isEqualToString:typeName]) { 164 | NSUInteger searchOptions = NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch; 165 | NSRange productNameRange = NSMakeRange(0, product.name.length); 166 | NSRange foundRange = [product.name rangeOfString:productName options:searchOptions range:productNameRange]; 167 | if (foundRange.length > 0) { 168 | [self.searchResults addObject:product]; 169 | } 170 | } 171 | } 172 | } 173 | 174 | @end 175 | -------------------------------------------------------------------------------- /Sample-UISearchController/Product.h: -------------------------------------------------------------------------------- 1 | // 2 | // TPSProduct.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import 12 | 13 | extern NSString *const ProductTypeDevice; 14 | extern NSString *const ProductTypeDesktop; 15 | extern NSString *const ProductTypePortable; 16 | 17 | @interface Product : NSObject 18 | 19 | @property (nonatomic, copy) NSString *name; 20 | @property (nonatomic, copy) NSString *type; 21 | 22 | + (NSArray *)allProducts; 23 | 24 | + (instancetype)productWithType:(NSString *)type name:(NSString *)name; 25 | 26 | + (NSArray *)deviceTypeNames; 27 | + (NSString *)displayNameForType:(NSString *)type; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Sample-UISearchController/Product.m: -------------------------------------------------------------------------------- 1 | // 2 | // TPSProduct.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import "Product.h" 12 | 13 | NSString *const ProductTypeDevice = @"Device"; 14 | NSString *const ProductTypeDesktop = @"Desktop"; 15 | NSString *const ProductTypePortable = @"Portable"; 16 | 17 | @implementation Product 18 | 19 | + (NSArray *)allProducts { 20 | return @[[Product productWithType:ProductTypeDevice name:@"iPhone"], 21 | [Product productWithType:ProductTypeDevice name:@"iPod"], 22 | [Product productWithType:ProductTypeDevice name:@"iPod touch"], 23 | [Product productWithType:ProductTypeDevice name:@"iPod nano"], 24 | [Product productWithType:ProductTypeDevice name:@"iPod classic"], 25 | [Product productWithType:ProductTypeDevice name:@"iPad"], 26 | [Product productWithType:ProductTypeDevice name:@"iPad mini"], 27 | [Product productWithType:ProductTypeDevice name:@"iPad Air"], 28 | [Product productWithType:ProductTypeDesktop name:@"iMac"], 29 | [Product productWithType:ProductTypeDesktop name:@"Mac Pro"], 30 | [Product productWithType:ProductTypeDesktop name:@"Mac mini"], 31 | [Product productWithType:ProductTypePortable name:@"MacBook"], 32 | [Product productWithType:ProductTypePortable name:@"MacBook Air"], 33 | [Product productWithType:ProductTypePortable name:@"MacBook Pro"]]; 34 | } 35 | 36 | + (instancetype)productWithType:(NSString *)type name:(NSString *)name { 37 | Product *newProduct = [[self alloc] init]; 38 | newProduct.type = type; 39 | newProduct.name = name; 40 | return newProduct; 41 | } 42 | 43 | 44 | + (NSArray *)deviceTypeNames { 45 | static NSArray *deviceTypeNames = nil; 46 | static dispatch_once_t once; 47 | 48 | dispatch_once(&once, ^{ 49 | deviceTypeNames = @[ProductTypeDevice, ProductTypePortable, ProductTypeDesktop]; 50 | }); 51 | 52 | return deviceTypeNames; 53 | } 54 | 55 | 56 | + (NSString *)displayNameForType:(NSString *)type { 57 | static NSMutableDictionary *deviceTypeDisplayNamesDictionary = nil; 58 | static dispatch_once_t once; 59 | 60 | dispatch_once(&once, ^{ 61 | deviceTypeDisplayNamesDictionary = [[NSMutableDictionary alloc] init]; 62 | for (NSString *deviceType in self.deviceTypeNames) { 63 | NSString *displayName = NSLocalizedString(deviceType, @"dynamic"); 64 | deviceTypeDisplayNamesDictionary[deviceType] = displayName; 65 | } 66 | }); 67 | 68 | return deviceTypeDisplayNamesDictionary[type]; 69 | } 70 | 71 | 72 | static NSString *const NameKey = @"NameKey"; 73 | static NSString *const TypeKey = @"TypeKey"; 74 | 75 | -(id)initWithCoder:(NSCoder *)aDecoder { 76 | self = [super init]; 77 | if (self) { 78 | _name = [aDecoder decodeObjectForKey:NameKey]; 79 | _type = [aDecoder decodeObjectForKey:TypeKey]; 80 | } 81 | return self; 82 | } 83 | 84 | -(void)encodeWithCoder:(NSCoder *)aCoder { 85 | [aCoder encodeObject:self.name forKey:NameKey]; 86 | [aCoder encodeObject:self.type forKey:TypeKey]; 87 | } 88 | 89 | @end -------------------------------------------------------------------------------- /Sample-UISearchController/SearchResultCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultCollectionViewCell.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/5/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SearchResultCollectionViewCell : UICollectionViewCell 12 | 13 | @property (nonatomic, weak) IBOutlet UILabel *titleLabel; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Sample-UISearchController/SearchResultCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultCollectionViewCell.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/5/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | 9 | #import "SearchResultCollectionViewCell.h" 10 | 11 | @implementation SearchResultCollectionViewCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | 16 | self.selectedBackgroundView = [[UIView alloc] init]; 17 | self.selectedBackgroundView.backgroundColor = [UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.0]; 18 | 19 | self.layer.borderColor = [[UIColor blackColor] CGColor]; 20 | self.layer.borderWidth = 1.0; 21 | self.layer.cornerRadius = 10.0; 22 | 23 | } 24 | @end 25 | -------------------------------------------------------------------------------- /Sample-UISearchController/SearchResultsCollectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultsCollectionViewController.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/5/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SearchResultsCollectionViewController : UICollectionViewController 12 | 13 | @property (nonatomic, strong) NSMutableArray *searchResults; // Filtered search results 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Sample-UISearchController/SearchResultsCollectionViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultsCollectionViewController.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/5/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | 9 | #import "SearchResultsCollectionViewController.h" 10 | #import "SearchResultCollectionViewCell.h" 11 | #import "DetailViewController.h" 12 | #import "Product.h" 13 | 14 | @interface SearchResultsCollectionViewController () 15 | 16 | @end 17 | 18 | @implementation SearchResultsCollectionViewController 19 | 20 | static NSString * const reuseIdentifier = @"SearchResultCell"; 21 | 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | self.collectionView.contentInset = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0); 26 | self.collectionView.scrollIndicatorInsets = UIEdgeInsetsMake(44.0, 0.0, 0.0, 0.0); 27 | } 28 | 29 | - (void)willMoveToParentViewController:(UIViewController *)parent { 30 | [super willMoveToParentViewController:parent]; 31 | } 32 | 33 | 34 | - (void)viewWillAppear:(BOOL)animated { 35 | [super viewWillAppear:animated]; 36 | [self.navigationController setNavigationBarHidden:YES animated:YES]; 37 | } 38 | 39 | #pragma mark 40 | 41 | 42 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 43 | return [self.searchResults count]; 44 | } 45 | 46 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 47 | 48 | SearchResultCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; 49 | 50 | // Configure the cell 51 | Product *product = [self.searchResults objectAtIndex:indexPath.row]; 52 | cell.titleLabel.text = product.name; 53 | 54 | return cell; 55 | } 56 | 57 | #pragma mark 58 | 59 | -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 60 | Product *product = [self.searchResults objectAtIndex:indexPath.row]; 61 | DetailViewController *vc = [[self storyboard] instantiateViewControllerWithIdentifier:@"DetailViewController"]; 62 | self.presentingViewController.navigationItem.title = @"Search"; 63 | vc.product = product; 64 | [self.presentingViewController.navigationController pushViewController:vc animated:YES]; 65 | } 66 | 67 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath 68 | { 69 | return YES; 70 | } 71 | 72 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath 73 | { 74 | return YES; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Sample-UISearchController/SearchResultsTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultsTableViewController.h 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 9/20/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SearchResultsTableViewController : UITableViewController 12 | 13 | @property (nonatomic, strong) NSMutableArray *searchResults; // Filtered search results 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Sample-UISearchController/SearchResultsTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SearchResultsTableViewController.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 9/20/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | 9 | #import "SearchResultsTableViewController.h" 10 | #import "DetailViewController.h" 11 | #import "Product.h" 12 | 13 | @implementation SearchResultsTableViewController 14 | 15 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 16 | return [self.searchResults count]; 17 | } 18 | 19 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 20 | 21 | UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"SearchResultCell" forIndexPath:indexPath]; 22 | 23 | Product *product = [self.searchResults objectAtIndex:indexPath.row]; 24 | 25 | cell.textLabel.text = product.name; 26 | 27 | return cell; 28 | 29 | } 30 | 31 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 32 | Product *product = [self.searchResults objectAtIndex:indexPath.row]; 33 | DetailViewController *vc = [[self storyboard] instantiateViewControllerWithIdentifier:@"DetailViewController"]; 34 | self.presentingViewController.navigationItem.title = @"Search"; 35 | vc.product = product; 36 | [self.presentingViewController.navigationController pushViewController:vc animated:YES]; 37 | } 38 | 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Sample-UISearchController/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Sample-UISearchController 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | // Based on Apple sample code TableSearch version 2.0 9 | // 10 | 11 | #import 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sample-UISearchControllerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | net.tapas-software.${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 | -------------------------------------------------------------------------------- /Sample-UISearchControllerTests/Sample_UISearchControllerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Sample_UISearchControllerTests.m 3 | // Sample-UISearchControllerTests 4 | // 5 | // Created by James Dempsey on 7/4/14. 6 | // Copyright (c) 2014 Tapas Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Sample_UISearchControllerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Sample_UISearchControllerTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | XCTAssert(YES, @"Pass"); 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | --------------------------------------------------------------------------------