iOS bluetooth's CBCentralManager not scanning devices after separating files - ios

I'm trying to get a list of bluetooth devices nearby and display it in a UItableview.
Originally I have this written in one view controller file using storyboard, and it worked, but now I'm separating the files to TableViewController, TableDelegate and TableDataSource, and writing this programmatically, and I'm not sure how to split the file up into 3 and have it work. This is what I have so far. It compiles, but CBCentralManager never scans the devices and call the centralManagerDidUpdateState function
The original code:
MasterViewController.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#interface MasterViewController ()
#property NSMutableArray *objects;
#end
#implementation MasterViewController
#pragma mark - CBCentralManagerDelegate
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if ([localName length] > 0) {
if (![_foundPeripherals containsObject:peripheral]) {
NSLog(#"Found: %#", localName);
[_foundPeripherals addObject:peripheral];
[_adData addObject:advertisementData];
[_RSSI addObject:RSSI];
[self.tableView reloadData];
//peripheral.delegate = self;
}
}
}
// method called whenever the device state changes.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if ([central state] == CBCentralManagerStatePoweredOn) {
NSLog(#"CoreBluetooth BLE hardware is powered on and ready");
NSArray *services = #[kDFUServiceUUID, kGuinnessServiceUUID, kHeartrateServiceUUID, kBatteryServiceUUID, kDeviceInfoServiceUUID];
NSDictionary *scanOptions = #{CBCentralManagerScanOptionAllowDuplicatesKey:#(YES)};
[self.centralManager scanForPeripheralsWithServices:services options:scanOptions];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
self.deviceData = nil;
_foundPeripherals = [[NSMutableArray alloc] init];
_adData = [[NSMutableArray alloc] init];
_RSSI = [[NSMutableArray alloc] init];
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
self.centralManager = centralManager;
}
- (void)viewWillDisappear:(BOOL)animated {
[_centralManager stopScan];
NSLog(#"Scanning stopped");
[super viewWillDisappear:animated];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Segues
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDate *object = self.objects[indexPath.row];
[[segue destinationViewController] setDetailItem:object];
}
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.foundPeripherals count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:simpleTableIdentifier];
}
CBPeripheral *peripheral=[_foundPeripherals objectAtIndex:indexPath.row];
cell.textLabel.text = peripheral.name;
return cell;
}
#end
New, separated code that doesn't work.
TableViewController.m
#import "TableViewController.h"
#import "TableDataSource.h"
#import "TableDelegate.h"
#interface TableViewController () {
TableDataSource *_dataSource;
TableDelegate *_delegate;
}
#end
#implementation TableViewController
- (void)loadView {
self.view = [[UIView alloc] init];
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
UITableView *tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStylePlain];
tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
self.view = tableView;
_dataSource = [[TableDataSource alloc] init];
_delegate = [[TableDelegate alloc] init];
_delegate.controller = self;
self.tableView.dataSource = _dataSource;
self.tableView.delegate = _delegate;
[self.tableView registerClass: [UITableViewCell class] forCellReuseIdentifier: #"device"];
}
- (void)viewDidLoad {
[super viewDidLoad];
[_dataSource getBluetoothDevices];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"reloadTable"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(checkRes:) name:#"reloadTable" object:nil];
}
-(void)checkRes:(NSNotification *)notification
{
if ([[notification name] isEqualToString:#"reloadTable"])
{
[self.tableView reloadData];
}
}
TableDelegate.h
#import <UIKit/UIKit.h>
#import CoreBluetooth;
#interface TableDelegate : NSObject <UITableViewDelegate, CBCentralManagerDelegate, CBPeripheralDelegate>
#property (nonatomic, weak) UIViewController *controller;
#end
TableDelegate.m
#import "TableDelegate.h"
#import "TableDataSource.h"
#import "DetailViewController.h"
#interface TableDelegate () {
TableDataSource *_dataSource;
}
#end
#implementation TableDelegate
- (instancetype)initWithDataSource:(TableDataSource *)dataSource {
self = [super init];
if (!self) return nil;
_dataSource = dataSource;
return self;
}
// method called whenever the device state changes.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if ([central state] == CBCentralManagerStatePoweredOn) {
NSLog(#"CoreBluetooth BLE hardware is powered on and ready");
NSArray *services = #[kDFUServiceUUID, kGuinnessServiceUUID, kHeartrateServiceUUID, kBatteryServiceUUID, kDeviceInfoServiceUUID];
NSDictionary *scanOptions = #{CBCentralManagerScanOptionAllowDuplicatesKey:#(YES)};
[_dataSource.centralManager scanForPeripheralsWithServices:services options:scanOptions];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath: indexPath animated: YES];
DetailViewController *detail = [[DetailViewController alloc] init];
[_controller.navigationController pushViewController: detail animated: YES];
}
#end
TableDataSource.m
#import "TableDataSource.h"
#import "TableViewController.h"
#import "TableDelegate.h"
#interface TableDataSource () {
TableDelegate *_delegate;
}
#end
#implementation TableDataSource
- (instancetype)initWithDelegate:(TableDelegate *)delegate {
self = [super init];
if (!self) return nil;
_delegate = delegate;
return self;
}
- (void)getBluetoothDevices
{
_foundPeripherals = [[NSMutableArray alloc] init];
_adData = [[NSMutableArray alloc] init];
_RSSI = [[NSMutableArray alloc] init];
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:_delegate queue:nil];
self.centralManager = centralManager;
}
// method called whenever you have successfully connected to the BLE peripheral
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if ([localName length] > 0) {
if (![_foundPeripherals containsObject:peripheral]) {
NSLog(#"Found: %#", localName);
[_foundPeripherals addObject:peripheral];
[_adData addObject:advertisementData];
[_RSSI addObject:RSSI];
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadTable" object:self];
//peripheral.delegate = self;
}
}
}
// method called whenever the device state changes.
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if ([central state] == CBCentralManagerStatePoweredOn) {
NSLog(#"CoreBluetooth BLE hardware is powered on and ready");
NSArray *services = #[kDFUServiceUUID, kGuinnessServiceUUID, kHeartrateServiceUUID, kBatteryServiceUUID, kDeviceInfoServiceUUID];
NSDictionary *scanOptions = #{CBCentralManagerScanOptionAllowDuplicatesKey:#(YES)};
[self.centralManager scanForPeripheralsWithServices:services options:scanOptions];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
[self getBluetoothDevices];
return [self.foundPeripherals count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"device";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:simpleTableIdentifier];
}
CBPeripheral *peripheral=[_foundPeripherals objectAtIndex:indexPath.row];
cell.textLabel.text = peripheral.name;
return cell;
}
#end

Related

My SearchDisplayController doesn't work well with UITableView in UIViewController

Here I have a Search Bar on the top of the UIViewController, and also a UITableView below the Search Bar.
When I don't Search things, the tableView could display things well, but when I search, the searchResultTableView can only show some white cell, not the correct result.
Here is the .h file:
#import <UIKit/UIKit.h>
#interface MySearchViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *myTableView;
- (void)reloadView;
#end
And here is the .m file:
#import "MySearchViewController.h"
#import "MyEventInfo.h"
#import "MyEventTableViewCell.h"
#import "MyEventDetailViewController.h"
#interface MySearchViewController ()
#property NSUserDefaults *usrDefault;
#end
#implementation MySearchViewController {
NSMutableArray *events;
NSArray *searchResults;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.usrDefault = [NSUserDefaults standardUserDefaults];
events = [[NSMutableArray alloc] init];
[self extractEventArrayData];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
[self reloadView];
}
- (void)reloadView {
NSLog(#"reloadView");
events = [[NSMutableArray alloc] init];
[self extractEventArrayData];
[self.myTableView reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)extractEventArrayData {
NSArray *dataArray = [[NSArray alloc] initWithArray:[self.usrDefault objectForKey:#"eventDataArray"]];
for (NSData *dataObject in dataArray) {
MyEventInfo *eventDecodedObject = [NSKeyedUnarchiver unarchiveObjectWithData:dataObject];
[events addObject:eventDecodedObject];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.myTableView) {
return [events count];
} else {
NSLog(#"searchResults count:%lu",(unsigned long)[searchResults count]);
return [searchResults count];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 360;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomTableCell";
MyEventTableViewCell *cell = (MyEventTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[MyEventTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Display MyEventTableViewCell in the table cell
MyEventInfo *event = nil;
if (tableView == self.myTableView) {
event = [events objectAtIndex:indexPath.row];
} else {
event = [searchResults objectAtIndex:indexPath.row];
NSLog(#"name of event:%#", event.nameOfEvent);
}
cell.nameOfEvent.text = event.nameOfEvent;
cell.imageOfEvent.image = [UIImage imageNamed:event.imageOfEvent];
cell.timeOfEvent.text = event.timeOfEvent;
cell.locationOfEvent.text = event.locationOfEvent;
cell.dateOfEvent.text = event.dateOfEvent;
return cell;
}
- (void)filterContentForSearchText:(NSString*)searchText
{
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"nameOfEvent contains[c] %#", searchText];
searchResults = [events filteredArrayUsingPredicate:resultPredicate];
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
[self filterContentForSearchText:searchString];
return YES;
}
#end
And on the storyboard I've already set the tableView's delegate and datasource to self. This drives me crazy, I cannot figure out what's wrong. Could someone help me out? Thanks.
when searching, cell's objects were all null, and had nothing in itself
when not searching, the cell is well with objects that had content the same as event

How Do I Display The Description Of An In-App Purchase Item?

I have a MasterViewController that shows a list of In-App Purchases in a table view. Whenever the table view cell is clicked, it presents my DetailViewController but it doesn't present the localized detail description for that In-App Purchase item. Is there a way so that depending on which IAP item was pressed in the tableview cell, it will present that IAP item's description in the DVC?
Here is my MVC.m:
#import "MasterViewController.h"
#import "DetailViewController.h"
#import "RageIAPHelper.h"
#import <StoreKit/StoreKit.h>
#interface MasterViewController () {
NSArray *_products;
NSNumberFormatter * _priceFormatter;
}
#end
#implementation MasterViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil];
[self.navigationItem setBackBarButtonItem:backButtonItem];
self.title = #"Settings";
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(reload) forControlEvents:UIControlEventValueChanged];
[self reload];
[self.refreshControl beginRefreshing];
_priceFormatter = [[NSNumberFormatter alloc] init];
[_priceFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[_priceFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Restore" style:UIBarButtonItemStylePlain target:self action:#selector(restoreTapped:)];
}
- (void)restoreTapped:(id)sender {
[[RageIAPHelper sharedInstance] restoreCompletedTransactions];
}
- (void)viewWillAppear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(productPurchased:) name:IAPHelperProductPurchasedNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)productPurchased:(NSNotification *)notification {
NSString * productIdentifier = notification.object;
[_products enumerateObjectsUsingBlock:^(SKProduct * product, NSUInteger idx, BOOL *stop) {
if ([product.productIdentifier isEqualToString:productIdentifier]) {
[self.tableView reloadRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:idx inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
*stop = YES;
}
}];
}
- (void)reload {
_products = nil;
[self.tableView reloadData];
[[RageIAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) {
if (success) {
_products = products;
[self.tableView reloadData];
}
[self.refreshControl endRefreshing];
}];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _products.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
SKProduct * product = (SKProduct *) _products[indexPath.row];
cell.textLabel.text = product.localizedTitle;
[_priceFormatter setLocale:product.priceLocale];
cell.detailTextLabel.text = [_priceFormatter stringFromNumber:product.price];
if ([[RageIAPHelper sharedInstance] productPurchased:product.productIdentifier]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.accessoryView = nil;
} else {
UIButton *buyButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
buyButton.frame = CGRectMake(0, 0, 72, 37);
[buyButton setTitle:#"Buy" forState:UIControlStateNormal];
buyButton.tag = indexPath.row;
[buyButton addTarget:self action:#selector(buyButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.accessoryView = buyButton;
}
return cell;
}
- (void)buyButtonTapped:(id)sender {
UIButton *buyButton = (UIButton *)sender;
SKProduct *product = _products[buyButton.tag];
NSLog(#"Buying %#...", product.productIdentifier);
[[RageIAPHelper sharedInstance] buyProduct:product];
}
#end
And here is my DetailViewController.h:
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
And my DetailViewController.m:
#import "DetailViewController.h"
#interface DetailViewController ()
- (void)configureView;
#end
#implementation DetailViewController
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
_detailDescriptionLabel.text = #"Please enable in app purchase in your settings";
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You should add this method your MasterVC.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
DetailViewController *dest = [segue destinationViewController];
UITableViewCell *cell = (UITableViewCell*)sender;
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
SKProduct *product = (SKProduct *) _products[indexPath.row];
dest.detailText = product.localizedDescription;
}
In DetailVC.h add:
#property (nonatomic, readwrite) NSString *detailText;
In DetailVC.m add:
- (void)viewWillAppear:(BOOL)animated {
self.detailDescriptionLabel.text = detailText;
}
Make sure you import your DetailViewController.h at the top of your MasterVC.m file.

PfqueryTableView with Search Bar Crashes

I am adding search bar to an app based on the Todo parse.com tutorial app. The search is working, but when I delete the search term, the app crashes. So for example, I type in an acronym "ABC" and it returns the values fine with a searchm as I delete "ABC" the app crashes with an out of bounds error.
#import "MyTableController.h"
#interface MyTableController() <UISearchDisplayDelegate> {
}
#property (nonatomic, strong) UISearchBar *searchBar;
#property (nonatomic, strong) UISearchDisplayController *searchController;
#property (nonatomic, strong) NSMutableArray *searchResults;
#end
#implementation MyTableController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
self.className = #"Jargon";
self.keyToDisplay = #"acronym";
self.pullToRefreshEnabled = YES;
self.paginationEnabled = YES;
self.objectsPerPage = 2;
}
return self;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
self.tableView.tableHeaderView = self.searchBar;
self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar
contentsController:self];
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;
self.searchController.delegate = self;
CGPoint offset = CGPointMake(0, self.searchBar.frame.size.height);
self.tableView.contentOffset = offset;
self.searchResults = [NSMutableArray array];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)filterResults:(NSString *)searchTerm {
[self.searchResults removeAllObjects];
PFQuery *query = [PFQuery queryWithClassName: self.className];
[query whereKey:#"acronym" containsString:searchTerm];
NSArray *results = [query findObjects:nil];
[self.searchResults addObjectsFromArray:results];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self filterResults:searchString];
return YES;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return self.objects.count ;
} else {
return self.searchResults.count +1;
}
}
#pragma mark - Parse
- (void)objectsDidLoad:(NSError *)error {
[super objectsDidLoad:error];
}
- (void)objectsWillLoad {
[super objectsWillLoad];
}
- (PFQuery *)queryForTable {
PFQuery *query = [PFQuery queryWithClassName:self.className];
if ([self.objects count] == 0) {
query.cachePolicy = kPFCachePolicyCacheThenNetwork;
}
[query orderByAscending:#"acronym"];
return query;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [object objectForKey:#"acronym"];
cell.detailTextLabel.text = [NSString stringWithFormat:#"Term: %#", [object objectForKey:#"text"]];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
}
#end

Protocol not implemented in 'AllListsViewController.m'; other errors

Am having protocol errors in AllListsViewController.m, but can't figure out why. Also have some other errors which I have commented out.
AllListsViewController.m
#import "AllListsViewController.h"
#import "ChecklistViewController.h"
#import "Checklist.h"
#import "ChecklistItem.h"
#interface AllListsViewController ()
#end
#implementation AllListsViewController
/* Method 'listDetailViewController:didFinishAddingChecklist' in protocol not implemented
Method 'listDetailViewController:didFinishEditingChecklist' in protocol not implemented
Method 'listDetailViewControllerDidCancel:' in protocol not implemented
*/
{
NSMutableArray *_lists;
}
-(NSString *)documentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];
return documentsDirectory;
}
-(NSString *)dataFilePath
{
return [[self documentsDirectory] stringByAppendingPathComponent:#"Checklists.plist"];
}
-(void)saveChecklistItems
{
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:_lists forKey:#"Checklists"];
[archiver finishEncoding];
[data writeToFile:[self dataFilePath] atomically:YES];
}
-(void)loadChecklists
{
NSString *path = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
_lists = [unarchiver decodeObjectForKey:#"Checklists"];
[unarchiver finishDecoding];
} else {
_lists = [[NSMutableArray alloc] initWithCapacity:20];
}
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder])) {
_lists = [[NSMutableArray alloc] initWithCapacity:20];
Checklist *list;
list = [[Checklist alloc] init];
list.name = #"Birthdays";
[_lists addObject:list];
list = [[Checklist alloc] init];
list.name = #"Groceries";
[_lists addObject:list];
list = [[Checklist alloc] init];
list.name = #"Cool Apps";
[_lists addObject:list];
list = [[Checklist alloc] init];
list.name = #"To Do";
[_lists addObject:list];
for (Checklist *list in _lists) {
ChecklistItem *item = [[ChecklistItem alloc] init];
item.text = [NSString stringWithFormat:#"Item for %#", list.name];
[list.items addObject:item];
[self loadChecklists];
}
return self;
}
- (void)viewDidLoad // Use of undeclared identifier 'viewDidLoad'
{
[super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [_lists count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
Checklist *checklist = _lists[indexPath.row];
cell.textLabel.text = checklist.name;
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Checklist *checklist = _lists[indexPath.row];
[self performSegueWithIdentifier:#"ShowChecklist" sender:checklist];
}
#pragma mark - Table View Delegate Protocol
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
[_lists removeObjectAtIndex:indexPath.row];
NSArray *indexPaths = #[indexPath];
[tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowChecklist"]) {
ChecklistViewController *controller = segue.destinationViewController;
controller.checklist = sender;
}
else if ([segue.identifier isEqualToString:#"AddChecklist"]) {
UINavigationController *navigationController = segue.destinationViewController;
ListDetailViewController *controller = (ListDetailViewController *)navigationController.topViewController;
controller.delegate = self;
controller.checklistToEdit = nil;
}
}
-(void)listDetailViewControllerDidCancel:(ListDetailViewController *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)listDetailViewController:(ListDetailViewController *)controller didFinishAddingChecklist:(Checklist *)checklist
{
NSInteger newRowIndex = [_lists count];
[_lists addObject:checklist];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:newRowIndex inSection:0];
NSArray *indexPaths = #[indexPath];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)listDetailViewController:(ListDetailViewController *)controller didFinishEditingChecklist:(Checklist *)checklist
{
NSInteger index = [_lists indexOfObject:checklist];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = checklist.name;
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
UINavigationController *navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"ListNavigationController"];
ListDetailViewController *controller = (ListDetailViewController *)navigationController.topViewController;
controller.delegate = self;
Checklist *checklist = _lists[indexPath.row];
controller.checklistToEdit = checklist;
[self presentViewController:navigationController animated:YES completion:nil];
}
#end // Missing "end" | Expected "}"
AllListsViewController.h
#import <UIKit/UIKit.h>
#import "ListDetailViewController.h"
#interface AllListsViewController : UITableViewController <ListDetailViewControllerDelegate>
#end
ListDetailViewController.h
#import <UIKit/UIKit.h>
#class ListDetailViewController;
#class Checklist;
#protocol ListDetailViewControllerDelegate <NSObject>
-(void)listDetailViewControllerDidCancel:(ListDetailViewController *)controller;
-(void)listDetailViewController:(ListDetailViewController *)controller didFinishAddingChecklist:(Checklist *)checklist;
-(void)listDetailViewController:(ListDetailViewController *)controller didFinishEditingChecklist:(Checklist *)checklist;
#end
#interface ListDetailViewController : UITableViewController
#property (nonatomic, weak) IBOutlet UITextField *textField;
#property (nonatomic, weak) IBOutlet UIBarButtonItem *doneBarButton;
#property (nonatomic, weak) id <ListDetailViewControllerDelegate> delegate;
#property (nonatomic, strong) Checklist *checklistToEdit;
-(IBAction)cancel;
-(IBAction)done;
#end
Based on the fact that you are getting errors about a missing end and "expected '}', it sounds like you have mismatched curly brackets in your code. This sort of thing is really hard to spot by looking at code, but quite easy in Xcode. double-tap on each opening curly brace and Xcode will select the entire contents of the block up to the closing brace. Do that in your AllListsViewController.m file until you find the opening curly brace that does not have a corresponding closing brace.

adding search to NSMutable Array with DetailView

i have project that I'm working on and i need to add search to my uitableview. i have been looking at lots of codes but mostly they are not what i am looking for and i can't modify them . can someone please help me with adding search to my tableview. also i want to push the detailview from searcharray. thank you in advance.
here is the .h uitableview
#import <UIKit/UIKit.h>
#interface Reds : UITableViewController {
NSMutableArray *dummyArray;
}
- (void) setupData;
#end
here is .m uitableview
#import "Reds.h"
#import "RedsDetail.h"
#interface Reds ()
#end
#implementation Reds
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupData];
}
- (void) setupData {
dummyArray = [[NSMutableArray alloc] init];
[dummyArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"dummy 1", #"name" , #"image1.JPG", #"image" , #"dummy 1 description textview", #"description", nil]];
[dummyArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"dummy 2", #"name" , #"image1.JPG", #"image" , #"dummy 2 description textview", #"description", nil]];
[dummyArray addObject:[[NSMutableDictionary alloc] initWithObjectsAndKeys:#"dummy 3", #"name" , #"image1.JPG", #"image" , #"dummy 3 description textview", #"description", nil]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [dummyArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [[dummyArray objectAtIndex:indexPath.row] objectForKey:#"name"];
return cell;
}
#pragma mark - Table view delegate
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"DummyDetail"]){
RedsDetail *dummyDetail = [segue destinationViewController];
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
dummyDetail.dummyImageString = [[NSString alloc] initWithString:[[dummyArray objectAtIndex:indexPath.row] objectForKey:#"image"]];
dummyDetail.dummyTextString = [[NSString alloc] initWithString:[[dummyArray objectAtIndex:indexPath.row] objectForKey:#"description"]];
dummyDetail.title = [[NSString alloc] initWithString:[[dummyArray objectAtIndex:indexPath.row] objectForKey:#"name"]];
}
}
#end
here is the .h detailview
#import <UIKit/UIKit.h>
#interface RedsDetail : UIViewController {
IBOutlet UIImageView *dummyImage;
IBOutlet UITextView *dummyText;
NSString *dummyImageString;
NSString *dummyTextString;
}
#property (nonatomic, retain) NSString *dummyImageString;
#property (nonatomic, retain) NSString *dummyTextString;
#end
and finally the .m detailview
#import "RedsDetail.h"
#interface RedsDetail ()
#end
#implementation RedsDetail
#synthesize dummyImageString, dummyTextString;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
dummyImage.image = [UIImage imageNamed:dummyImageString];
dummyText.text = dummyTextString;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
i know it might be a easy answer for most of you guys out there but i can't figure it out and i need help. i truly appreciate the time you guys spending in helping me. also i am using xcode 4.5 ios 6 storyboard if that makes a difference in your answers.
adrian
For the search, create a searchArray and a searchText, also you need a textfield that invokes the didChange method.
Use this to link the textfield to the didChange method:
[self.searchTextField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
Then in the didChange update the searchText and call the updateSearchArray.
-(void)textFieldDidChange:(UITextField*)textField
{
searchTextString = textField.text;
[self updateSearchArray];
}
In the updateSearchArray you compare go through the original array (dummyArray) and if the name is included in the search then add it to the searchArray.
-(void)updateSearchArray
{
if (searchTextString.length != 0) {
searchArray = [NSMutableArray array];
for ( NSDictionary* item in dummyArray ) {
if ([[[item objectForKey:#"name"] lowercaseString] rangeOfString:[searchTextString lowercaseString]].location != NSNotFound) {
[searchArray addObject:item];
}
}
} else {
searchArray = dummyArray;
}
[self.tableView reloadData];
}
Use the searchArray in the tableview methods where you now use the dummyArray.
Updated tableview methods
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [searchArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [[searchArray objectAtIndex:indexPath.row] objectForKey:#"name"];
return cell;
}
Also, you need to call a reloadData after adding all the data to the array. And added the updateSearchArray method
- (void)viewDidLoad
{
[super viewDidLoad];
[self setupData];
[self updateSearchArray];
[self.tableView reloadData];
}
To make it easier to implement this I have made a sample project. You can download it here: http://www.rolandkeesom.com/SearchExample.zip

Resources