I'm using a combination of SWRevealViewController, A ContentViewController and A NavigationViewController (Navigation).
The storyboard is as follows:
On TableViewCell click I can get the navigation text. What I want to be able to do is to pass this information back into itself. Setting the title of the ContentViewController to the selected cell and loading other desired data.
How can I fulfil this functionality?
Here is my latest code within my NavigationViewController.m file:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL isChild = currentExpandedIndex > -1 && indexPath.row > currentExpandedIndex && indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
UITableViewCell *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath];
if (isChild) {
NSString *cellText = selectedCell.detailTextLabel.text;
NSLog(#"%# tapped",cellText);
return;
}
else{
NSString *cellText = selectedCell.textLabel.text;
NSLog(#"%# tapped",cellText);
if([cellText isEqualToString:#"Sign Out"]){
[self performSegueWithIdentifier:#"goToHome" sender:self];
}
else if ([cellText isEqualToString:#"Sign In"]){
[self performSegueWithIdentifier:#"goToHome" sender:self];
}
else if ([cellText isEqualToString:#"Festival Map"]){
[self performSegueWithIdentifier:#"festivalMap" sender:self];
}
}
[self.tableView beginUpdates];
if (currentExpandedIndex == indexPath.row) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
currentExpandedIndex = -1;
}
else {
BOOL shouldCollapse = currentExpandedIndex > -1;
if (shouldCollapse) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
}
currentExpandedIndex = (shouldCollapse && indexPath.row > currentExpandedIndex) ? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] : indexPath.row;
[self expandItemAtIndex:currentExpandedIndex];
}
[self.tableView endUpdates];
}
- (void)expandItemAtIndex:(int)index {
NSMutableArray *indexPaths = [NSMutableArray new];
NSArray *currentSubItems = [subItems objectAtIndex:index];
int insertPos = index + 1;
for (int i = 0; i < [currentSubItems count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:insertPos++ inSection:0]];
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
}
- (void)collapseSubItemsAtIndex:(int)index {
NSMutableArray *indexPaths = [NSMutableArray new];
for (int i = index + 1; i <= index + [[subItems objectAtIndex:index] count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"festivalMap"]){
NSLog(#"TEST");
NSString * title = #"CHANGE";
ViewController * view = [segue destinationViewController];
view.navigationItem.title = title;
}
}
And here is the code for my ContentViewController.m file:
#import "ContentViewController.h"
#import "SWRevealViewController.h"
#import "Function.h"
#interface ContentViewController ()
#end
#implementation ContentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_barButton.target = self.revealViewController;
_barButton.action = #selector(revealToggle:);
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
}
#end
Thanks
You can Try this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"yoursegue"]){
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UITableViewCell *selectedCell = [self.tableView cellForRowAtIndexPath:indexPath];
ContentViewController*contentView = (ContentViewController*)segue.destinationViewController;
contentView.cellText = selectedCell.textLabel.text;
NSLog(#"cellText = %#",selectedCell.textLabel.text;);
}
}
However, it is not good practice to access value from the user interface or build the logic around it, instead you should be using the datasource.This violate MVC principles.
Related
When a row is deleted it always slides to left no matter what animation value I pass. I would like it to slide up similar to many of the stock apps.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
self.tableData = [][[self.tableData mutableCopy] removeObjectAtIndex:indexPath.row] copy];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
}
Here is the full tableview controller code, it is has a lot in it. That is the reason I didn't post it at first.
#interface FMListViewController ()
#property (strong) NSArray *currentLocations;
#property (assign) BOOL isEditing;
#end
#implementation FMListViewController
- (void)viewDidLoad {
[super viewDidLoad];
UISegmentedControl *viewType = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"List", #"Map", nil]];
CGRect viewTypeRect = viewType.frame;
viewTypeRect.size.width = 150.0f;
viewType.frame = viewTypeRect;
viewType.selectedSegmentIndex = 0;
[viewType addTarget:self action:#selector(viewTypeChange:) forControlEvents:UIControlEventValueChanged];
self.navigationItem.titleView = viewType;
self.currentLocations = [[FMLocations sharedManager] allLocations];
//watch for weather updates
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(weatherUpdated) name:#"weatherUpdated" object:nil];
//watch for changes to saved locations
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(locationsUpdated) name:#"locationsUpdated" object:nil];
self.isEditing = NO;
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
// this UIViewController is about to re-appear, make sure we remove the current selection in our table view when swiping back occurs
NSIndexPath *tableSelection = [self.tableView indexPathForSelectedRow];
[self.tableView deselectRowAtIndexPath:tableSelection animated:NO];
[self.navigationController setToolbarHidden:YES animated:NO];
}
- (void)viewTypeChange:(UISegmentedControl *)segControl{
NSLog(#"change to map");
[(FMNavController *)[self navigationController] changeViewType];
segControl.selectedSegmentIndex = 0;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)weatherUpdated{
[self.tableView reloadData];
[self.refreshControl endRefreshing];
}
- (void)locationsUpdated{
if(self.isEditing){
self.currentLocations = [[FMLocations sharedManager] savedLocations];
}else{
self.currentLocations = [[FMLocations sharedManager] allLocations];
}
[self.tableView reloadData];
}
#pragma mark - Table Editing Stuff
- (IBAction)toggleEditing:(id)sender{
if(self.isEditing){
self.isEditing = NO;
self.currentLocations = [[FMLocations sharedManager] allLocations];
[self.tableView reloadData];
UIBarButtonItem *newRightItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:#selector(toggleEditing:)];
self.navigationItem.rightBarButtonItem = newRightItem;
[self.tableView setEditing:NO animated:YES];
}else{
self.isEditing = YES;
self.currentLocations = [[FMLocations sharedManager] savedLocations];
[self.tableView reloadData];
UIBarButtonItem *newRightItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(toggleEditing:)];
self.navigationItem.rightBarButtonItem = newRightItem;
[self.tableView setEditing:YES animated:YES];
}
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row == 0 && [[FMLocations sharedManager] currentLocation] && !self.isEditing){
return NO;
}
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
NSMutableArray *newLocations;
int arrayOffset = 0;
if([[FMLocations sharedManager] currentLocation] && !self.isEditing){
arrayOffset = -1;
}
newLocations = [[[FMLocations sharedManager] savedLocations] mutableCopy];
int itemToRemove = (int)indexPath.row + arrayOffset;
if(itemToRemove < 0 || itemToRemove > [newLocations count]){
NSLog(#"invalid item to remove");
}else{
[newLocations removeObjectAtIndex:itemToRemove];
[[FMLocations sharedManager] saveSavedLocations:[newLocations copy]];
if(self.isEditing){
self.currentLocations = [[FMLocations sharedManager] savedLocations];
}else{
self.currentLocations = [[FMLocations sharedManager] allLocations];
}
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row == 0 && [[FMLocations sharedManager] currentLocation] && !self.isEditing){
return NO;
}
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
NSMutableArray *editableLocations = [[[FMLocations sharedManager] savedLocations] mutableCopy];
if(editableLocations && [editableLocations count] > sourceIndexPath.row && [editableLocations count] > destinationIndexPath.row){
NSInteger fromIndex = sourceIndexPath.row;
NSInteger toIndex = destinationIndexPath.row;
id object = [editableLocations objectAtIndex:fromIndex];
[editableLocations removeObjectAtIndex:fromIndex];
[editableLocations insertObject:object atIndex:toIndex];
[[FMLocations sharedManager] saveSavedLocations:[editableLocations copy]];
}
}
#pragma mark - Refresh control action
- (IBAction)doRefreshTable:(id)sender{
[[ForecastManager sharedManager] updateForecasts];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [self.currentLocations count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"getting cell");
FMTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"FMLocationCell" forIndexPath:indexPath];
NSDictionary *theLocation = [self.currentLocations objectAtIndex:indexPath.row];
// Configure the cell...
cell.locationLabel.text = [[theLocation objectForKey:#"name"] uppercaseString];
WeatherObject *locationWeather = [[ForecastManager sharedManager] weatherObjectForLocation:[[theLocation objectForKey:#"id"] intValue]];
[cell setCurrentTemp:locationWeather.currentTemp];
[cell configureForecastViews:locationWeather.forecastObjects];
[cell.weatherPreviewContainer setNeedsDisplay];
return cell;
}
#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 {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if([segue.identifier isEqualToString:#"showLocation"]){
FMDetailViewController *detailController = [segue destinationViewController];
NSDictionary *theLocation = [self.currentLocations objectAtIndex:self.tableView.indexPathForSelectedRow.row];
detailController.navigationItem.title = [theLocation objectForKey:#"name"];
detailController.detailLocation = theLocation;
}
}
You can try below solutions:
1) Replace your line with the below one
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationTop];
2) Change the code with the below one:
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
Hope this helps!
please try with that
don't delete cell directly first make its cellheight to zero using. NSIndexPath *deleteIndexPath;
wirte below code before delete
[tbl beginUpdates];
deleteIndexPath = indexPath;
[tbl reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tbl endUpdates];
and in set hight method use
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{ if (indexPath == deleteIndexPath) {
return 0;
}
return 50;
}
I have this code and I am trying to understand it. This has an int value 'currentExpandIndex' ,I couldnt figure out why it is changing because I dont find proper initiation of it. The int is first given the value -1,but later in code the int value changes according to the indexpath. I coldnt find the relation between the int and the indexpath declared in the code.Kindly tell me,why
the code is:
#interface AccordionTableViewController : UITableViewController {
NSArray *topItems;
NSMutableArray *subItems; // array of arrays
int currentExpandedIndex;
}
#end
//.m file
- (id)init {
self = [super init];
if (self) {
topItems = [[NSArray alloc] initWithArray:[self topLevelItems]];
subItems = [NSMutableArray new];
currentExpandedIndex = -1;
NSLog(#"currenyt index -init is %d",currentExpandedIndex);
for (int i = 0; i < [topItems count]; i++) {
[subItems addObject:[self subItems]];
}
}
return self;
}
#pragma mark - Data generators
- (NSArray *)topLevelItems {
NSMutableArray *items = [NSMutableArray array];
for (int i = 0; i < NUM_TOP_ITEMS; i++) {
[items addObject:[NSString stringWithFormat:#"Item %d", i + 1]];
}
return items;
}
- (NSArray *)subItems {
NSMutableArray *items = [NSMutableArray array];
int numItems = arc4random() % NUM_SUBITEMS + 2;
for (int i = 0; i < numItems; i++) {
[items addObject:[NSString stringWithFormat:#"SubItem %d", i + 1]];
}
return items;
}
#pragma mark - View management
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"currenyt index -view did load is %d",currentExpandedIndex);
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"currenyt index -no of rows in section is %d",currentExpandedIndex);
return [topItems count] + ((currentExpandedIndex > -1) ? [[subItems objectAtIndex:currentExpandedIndex] count] : 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ParentCellIdentifier = #"ParentCell";
static NSString *ChildCellIdentifier = #"ChildCell";
NSLog(#"currenyt index-cell for row at index is %d",currentExpandedIndex);
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
UITableViewCell *cell;
if (isChild) {
cell = [tableView dequeueReusableCellWithIdentifier:ChildCellIdentifier];
}
else {
cell = [tableView dequeueReusableCellWithIdentifier:ParentCellIdentifier];
}
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ParentCellIdentifier] autorelease];
}
if (isChild) {
cell.detailTextLabel.text = [[subItems objectAtIndex:currentExpandedIndex] objectAtIndex:indexPath.row - currentExpandedIndex - 1];
}
else {
int topIndex = (currentExpandedIndex > -1 && indexPath.row > currentExpandedIndex)
? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count]
: indexPath.row;
cell.textLabel.text = [topItems objectAtIndex:topIndex];
cell.detailTextLabel.text = #"";
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
if (isChild) {
NSLog(#"A child was tapped, do what you will with it");
NSLog(#"currenyt index -did select is %d",currentExpandedIndex);
return;
}
NSLog(#"currenyt index -did select out is %d",currentExpandedIndex);
[self.tableView beginUpdates];
if (currentExpandedIndex == indexPath.row) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
currentExpandedIndex = -1;
}
else {
BOOL shouldCollapse = currentExpandedIndex > -1;
if (shouldCollapse) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
}
currentExpandedIndex = (shouldCollapse && indexPath.row > currentExpandedIndex) ? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] : indexPath.row;
[self expandItemAtIndex:currentExpandedIndex];
}
[self.tableView endUpdates];
}
- (void)expandItemAtIndex:(int)index {
NSMutableArray *indexPaths = [NSMutableArray new];
NSArray *currentSubItems = [subItems objectAtIndex:index];
int insertPos = index + 1;
for (int i = 0; i < [currentSubItems count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:insertPos++ inSection:0]];
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
//[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
[indexPaths release];
}
- (void)collapseSubItemsAtIndex:(int)index {
NSMutableArray *indexPaths = [NSMutableArray new];
for (int i = index + 1; i <= index + [[subItems objectAtIndex:index] count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[indexPaths release];
}
In didSelectRowAtIndexPath: you have this line:
currentExpandedIndex =
(shouldCollapse && indexPath.row > currentExpandedIndex) ?
indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] :
indexPath.row;
This line assign indexPath.row or indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] to currentExpandedIndex.
currentExpandedIndex = (shouldCollapse && indexPath.row > currentExpandedIndex) ? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] : indexPath.row;
On each didSelectRow it will change.
First, set a breakpoint in -init. Depending on how you create this controller, it might not be called, in which case it will be 0. Try -initWithCoder: instead if this is the case. Otherwise, I only see this set in one place: -tableView:didSelectRowAtIndexPath:, where it can be set to the row or indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count]. Depending on what else you are doing with the table, this might be a good job for sections or expandable individual rows to simplify.
Good day! My default tableview sectionHeaderHeight is 56. I want to update it when sectionOpened method gets called.This is the following code:
- (void) sectionOpened : (NSInteger) section
{
sectionHeight = #"YES";
getsection = section;
NSLog(#"Section Clicked: %ld",(long)getsection);
SectionInfo *array = [self.sectionInfoArray objectAtIndex:section];
array.open = YES;
NSInteger count = [array.category.menulist count];
NSMutableArray *indexPathToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i<count;i++)
{
[indexPathToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenIndex = self.openSectionIndex;
if (previousOpenIndex != NSNotFound)
{
SectionInfo *sectionArray = [self.sectionInfoArray objectAtIndex:previousOpenIndex];
sectionArray.open = NO;
NSInteger counts = [sectionArray.category.menulist count];
[sectionArray.sectionView toggleButtonPressed:FALSE];
for (NSInteger i = 0; i<counts; i++)
{
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenIndex]];
}
}
UITableViewRowAnimation insertAnimation;
UITableViewRowAnimation deleteAnimation;
if (previousOpenIndex == NSNotFound || section < previousOpenIndex)
{
insertAnimation = UITableViewRowAnimationTop;
deleteAnimation = UITableViewRowAnimationBottom;
}
else
{
insertAnimation = UITableViewRowAnimationBottom;
deleteAnimation = UITableViewRowAnimationTop;
}
[menulistTable beginUpdates];
if(section==3 || section==4 || section==5) // this section has cells like submenu of a menu
{
menulistTable.sectionHeaderHeight = 20.0;
[menulistTable reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationNone];
//[menulistTable reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
}
[menulistTable insertRowsAtIndexPaths:indexPathToInsert withRowAnimation:insertAnimation];
[menulistTable deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:deleteAnimation];
[menulistTable endUpdates];
self.openSectionIndex = section;
}
But nothing happening. I also used indexSetWithIndex:0. Whats wrong in the code?
Try like this to change Height:
[menulistTable beginUpdates];
menulistTable.sectionHeaderHeight = 20.0;
[menulistTable endUpdates];
Edited:
Take variable to set SectionHeaderHeight. Then place this code:
[menulistTable beginUpdates];
secHeaderHeight = 20.0;
[menulistTable endUpdates];
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return secHeaderHeight;
}
Hope it will work for you.
I am relatively new in iOS, I have found an example of accordion table view that I need. But the thing is that example is TableViewController and I need to implement TableView inside viewController. Can you please help me. What I have tried to do is create tableView, declare it in the h file as
#property (strong, nonatomic) IBOutlet UITableView *MyTb;
and then change all appearances of self.tableView to self.MyTb but it did not work, oh also changed
AccordionTableViewController : UITableViewController
to
AccordionTableViewController : UIViewController
So here is the original code, please help me and provide some guiadance to it, thanks.
h file:
#import <UIKit/UIKit.h>
#interface AccordionTableViewController : UITableViewController {
NSArray *topItems;
NSMutableArray *subItems; // array of arrays
int currentExpandedIndex;
}
#end
m file:
#import "AccordionTableViewController.h"
#define NUM_TOP_ITEMS 20
#define NUM_SUBITEMS 6
#implementation AccordionTableViewController
- (id)init {
self = [super init];
if (self) {
topItems = [[NSArray alloc] initWithArray:[self topLevelItems]];
subItems = [NSMutableArray new];
currentExpandedIndex = -1;
for (int i = 0; i < [topItems count]; i++) {
[subItems addObject:[self subItems]];
}
}
return self;
}
#pragma mark - Data generators
- (NSArray *)topLevelItems {
NSMutableArray *items = [NSMutableArray array];
for (int i = 0; i < NUM_TOP_ITEMS; i++) {
[items addObject:[NSString stringWithFormat:#"Item %d", i + 1]];
}
return items;
}
- (NSArray *)subItems {
NSMutableArray *items = [NSMutableArray array];
int numItems = arc4random() % NUM_SUBITEMS + 2;
for (int i = 0; i < numItems; i++) {
[items addObject:[NSString stringWithFormat:#"SubItem %d", i + 1]];
}
return items;
}
#pragma mark - View management
- (void)viewDidLoad {
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [topItems count] + ((currentExpandedIndex > -1) ? [[subItems objectAtIndex:currentExpandedIndex] count] : 0);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ParentCellIdentifier = #"ParentCell";
static NSString *ChildCellIdentifier = #"ChildCell";
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
UITableViewCell *cell;
if (isChild) {
cell = [tableView dequeueReusableCellWithIdentifier:ChildCellIdentifier];
}
else {
cell = [tableView dequeueReusableCellWithIdentifier:ParentCellIdentifier];
}
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ParentCellIdentifier] autorelease];
}
if (isChild) {
cell.detailTextLabel.text = [[subItems objectAtIndex:currentExpandedIndex] objectAtIndex:indexPath.row - currentExpandedIndex - 1];
}
else {
int topIndex = (currentExpandedIndex > -1 && indexPath.row > currentExpandedIndex)
? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count]
: indexPath.row;
cell.textLabel.text = [topItems objectAtIndex:topIndex];
cell.detailTextLabel.text = #"";
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
BOOL isChild =
currentExpandedIndex > -1
&& indexPath.row > currentExpandedIndex
&& indexPath.row <= currentExpandedIndex + [[subItems objectAtIndex:currentExpandedIndex] count];
if (isChild) {
NSLog(#"A child was tapped, do what you will with it");
return;
}
[self.tableView beginUpdates];
if (currentExpandedIndex == indexPath.row) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
currentExpandedIndex = -1;
}
else {
BOOL shouldCollapse = currentExpandedIndex > -1;
if (shouldCollapse) {
[self collapseSubItemsAtIndex:currentExpandedIndex];
}
currentExpandedIndex = (shouldCollapse && indexPath.row > currentExpandedIndex) ? indexPath.row - [[subItems objectAtIndex:currentExpandedIndex] count] : indexPath.row;
[self expandItemAtIndex:currentExpandedIndex];
}
[self.tableView endUpdates];
}
- (void)expandItemAtIndex:(int)index
{
NSMutableArray *indexPaths = [NSMutableArray new];
NSArray *currentSubItems = [subItems objectAtIndex:index];
int insertPos = index + 1;
for (int i = 0; i < [currentSubItems count]; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:insertPos++ inSection:0]];
}
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
//[indexPaths release];
}
- (void)collapseSubItemsAtIndex:(int)index
{
NSMutableArray *indexPaths = [NSMutableArray new];
for (int i = index + 1; i <= index + [[subItems objectAtIndex:index] count]; i++)
{
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
//[indexPaths release];
}
- (void)dealloc
{
[topItems release];
[subItems release];
[super dealloc];
}
#end
You must set your view controller as delegate and datasource of your tableview:
#interface AccordionTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
in your header file and in viewDidLoad:
-(void)viewDidLoad {
[super viewDidLoad];
self.MyTb.delegate = self;
self.MyTb.dataSource = self;
}
Or you can set the datasource and delegate in Storyboard. You must also make sure you have connected the table view to MyTb IBOutlet in storyboard.
I'm am working on using BLE on a project previously using MFi devices.
The goal is to achieve a sort of serial connection.
With EAaccessory I had a popover asking for the device to connect to and was working fine.
Using CB, I added a view that I call to scan and select the device to connect to.
I can connect the device fine, but when I go back to main view, I loose the connection to the peripheral.
CoreBluetooth[WARNING] <CBConcretePeripheral: ... IsConnected = YES> is being dealloc'ed while connected
So, as I am not a genius nor a good iOs programmer...
Could someone point me in the right direction to retain the connected peripheral from one view to the main ?
I tried to understand a sample from ConnectBlue, the manufacturer of the BT devices on my project, but they use Storyboard, and I don't.
Using their demo, I can connect to the peripheral, on the main view and chat with it on another view.
I tried to google, but found nothing relevant.
Edit:
The connection code part
#import "ScanTableViewController.h"
#import <CoreBluetooth/CBCentralManager.h>
#import <CoreBluetooth/CBPeripheral.h>
#import "DiscoveredPeripheral.h"
#import "ScanCell.h"
typedef enum
{
SCAN_S_NOT_LOADED,
SCAN_S_DISAPPEARED,
SCAN_S_WILL_DISAPPEAR,
SCAN_S_APPEARED_IDLE,
SCAN_S_APPEARED_SCANNING
} SCAN_State;
#interface ScanTableViewController ()
#end
#implementation ScanTableViewController
{
SCAN_State state;
CBCentralManager *cbCentralManager;
NSMutableArray *discoveredPeripherals;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Scan viewDidLoad");
cbCentralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
// Do any additional setup after loading the view from its nib.
CGRect tableViewFrame = self.view.bounds;
UITableView *tableview = [[UITableView alloc] initWithFrame:tableViewFrame style:UITableViewStylePlain];
self.myTableView = tableview;
self.myTableView.rowHeight = 60;
self.myTableView.dataSource = self;
self.myTableView.delegate = self;
//Make sure our table view resizes correctly
self.myTableView.autoresizingMask =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
[self.view addSubview:tableview];
discoveredPeripherals = [[NSMutableArray alloc] init];
//[cbCentralManager retrieveConnectedPeripherals];
state = SCAN_S_DISAPPEARED;
}
- (void)viewDidUnload
{
//[self setScanButton:nil];
[super viewDidUnload];
NSLog(#"Scan viewDidUnload");
cbCentralManager = nil;
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
state = SCAN_S_NOT_LOADED;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(#"Scan viewWillAppear");
[self.myTableView reloadData];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(#"Scan viewDidAppear");
[self clearPeriph];
state = SCAN_S_APPEARED_IDLE;
[self.myTableView reloadData];
}
- (void)viewWillDisappear:(BOOL)animated
{
NSLog(#"Scan viewWillDisappear");
//[self scan: FALSE];
state = SCAN_S_WILL_DISAPPEAR;
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSLog(#"Scan viewDidDisappear");
state = SCAN_S_DISAPPEARED;
}
-(void) enterForeground
{
NSLog(#"Scan enterForeground");
[self clearPeriph];
state = SCAN_S_APPEARED_IDLE;
}
-(void) enterBackground
{
NSLog(#"Scan enterBackground");
[self scan: FALSE];
state = SCAN_S_DISAPPEARED;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) initWithPeripherals: (NSMutableArray*) dp
{
NSLog(#"Scan initWithPeripherals");
discoveredPeripherals = dp;
state = SCAN_S_NOT_LOADED;
}
#pragma mark - Table view data source
// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
//NSLog(#"Nombre de sections");
return 2;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSInteger nRows;
switch(section)
{
case 0:
nRows = 1;
break;
case 1:
NSLog(#"Scan Nbre ligne section 1 : %i",discoveredPeripherals.count);
nRows = discoveredPeripherals.count;
break;
default:
nRows = 0;
break;
}
return nRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"Remplissage");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
cell.accessoryType=UITableViewCellAccessoryDetailDisclosureButton;
}
NSLog(#"Scan Section table:%u",indexPath.section);
switch(indexPath.section)
{
case 0:
{
cell.textLabel.text = #"";
if(state == SCAN_S_APPEARED_SCANNING)
{
cell.textLabel.text = #"Stop Scan";
//cell.labelInfo.text = #"Active";
//[cell.activityView startAnimating];
}
else
{
cell.textLabel.text = #"Start Scan";
//cell.labelInfo.text = #"Inactive";
//
//[cell.activityView stopAnimating];
}
break;
}
case 1:
{
if ( [discoveredPeripherals count] > 0)
{
DiscoveredPeripheral* discoveredPeripheral;
discoveredPeripheral = [discoveredPeripherals objectAtIndex:indexPath.row];
cell.textLabel.text =discoveredPeripheral.peripheral.name;
}
cell.detailTextLabel.textColor = [UIColor blackColor];
}
}
return cell;
}
- (NSString*) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *str;
switch(section)
{
case 0:
str = #"Bluetooth Low Energy Scanning";
break;
case 1:
str = #"Found Devices";
break;
default:
break;
}
return str;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(cbCentralManager.state == CBCentralManagerStatePoweredOn)
{
//ScanCell* cell = (ScanCell*)[tableView cellForRowAtIndexPath:indexPath];
//static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if(indexPath.section == 0)
{
if(state == SCAN_S_APPEARED_SCANNING)
{
[self scan: FALSE];
cell.textLabel.text = #"Start Scan";
//cell.labelInfo.text = #"Inactive";
//[cell.activityView stopAnimating];
state = SCAN_S_APPEARED_IDLE;
}
else if((state == SCAN_S_APPEARED_IDLE) &&
(cbCentralManager.state == CBCentralManagerStatePoweredOn))
{
[self scan: TRUE];
cell.textLabel.text = #"Stop Scan";
//cell.labelInfo.text = #"Active";
//[cell.activityView startAnimating];
state = SCAN_S_APPEARED_SCANNING;
}
}
else
{
DiscoveredPeripheral* dp = [discoveredPeripherals objectAtIndex:indexPath.row];
NSDictionary *dictionary;
switch (dp.state)
{
case DP_STATE_IDLE:
cell.textLabel.text = #"Connecting";
//[cell.activityView startAnimating];
dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];
[cbCentralManager connectPeripheral:dp.peripheral options:dictionary];
dp.state = DP_STATE_CONNECTING;
break;
case DP_STATE_CONNECTED:
case DP_STATE_CONNECTING:
[cbCentralManager cancelPeripheralConnection:dp.peripheral];
cell.textLabel.text = #"";
//[cell.activityView stopAnimating];
cell.accessoryType = UITableViewCellAccessoryNone;
dp.state = DP_STATE_IDLE;
break;
default:
break;
}
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
- (void) scan: (bool) enable
{
if(enable == TRUE)
{
NSLog(#"Scan Scan ON");
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1] forKey:CBCentralManagerScanOptionAllowDuplicatesKey];
[cbCentralManager scanForPeripheralsWithServices:nil options:dictionary];
}
else
{
NSLog(#"Scan Scan Off");
[cbCentralManager stopScan];
}
}
- (IBAction)startScan:(id)sender {
if(state == SCAN_S_APPEARED_IDLE)
{
[self scan: TRUE];
state = SCAN_S_APPEARED_SCANNING;
}
else if(state == SCAN_S_APPEARED_SCANNING)
{
[self scan: FALSE];
state = SCAN_S_APPEARED_IDLE;
}
}
- (void) clearPeriphForRow: (NSInteger)row
{
DiscoveredPeripheral* dp = [discoveredPeripherals objectAtIndex:row];
//if( (dp.peripheral.isConnected == FALSE) &&
// ( (dp.state == DP_STATE_CONNECTED) || (dp.state == DP_STATE_DISCONNECTING)))
if(dp.peripheral.isConnected == FALSE)
{
dp.state = DP_STATE_IDLE;
}
else if( (dp.peripheral.isConnected == TRUE) &&
(dp.state != DP_STATE_CONNECTED))
{
dp.state = DP_STATE_CONNECTED;
}
if(dp.state == DP_STATE_IDLE)
{
[discoveredPeripherals removeObjectAtIndex:row];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:1];
//ScanCell* cell = (ScanCell*)[self.tableView cellForRowAtIndexPath:indexPath];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
//[cell.activityView stopAnimating];
cell.accessoryType = UITableViewCellAccessoryNone;
[self.myTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void) clearPeriph
{
if(self->discoveredPeripherals.count > 0)
{
for(int i = discoveredPeripherals.count - 1; i >= 0 ; i--)
{
[self clearPeriphForRow:i];
}
}
[self.myTableView reloadData];
}
- (IBAction)clearPeripherals:(id)sender {
[self clearPeriph];
[self scan: FALSE];
state = SCAN_S_APPEARED_IDLE;
}
- (NSInteger)getRowForPeripheral: (CBPeripheral*)peripheral
{
NSInteger row = -1;
DiscoveredPeripheral* p;
for(int i = 0; (i < discoveredPeripherals.count) && (row == -1); i++)
{
p = [discoveredPeripherals objectAtIndex:i];
if([peripheral isEqual:p.peripheral] == TRUE)
{
row = i;
}
}
return row;
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSInteger row = [self getRowForPeripheral:peripheral];
if(row != -1)
{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:1];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
//ScanCell* cell = (ScanCell*)[self.tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = [[NSString alloc] initWithFormat:#"Connected"];
//[cell.activityView stopAnimating];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
DiscoveredPeripheral* dp = [discoveredPeripherals objectAtIndex:row];
dp.state = DP_STATE_CONNECTED;
//[peripheral discoverServices:nil];
//[self scan:FALSE];
//[[self navigationController] popViewControllerAnimated:NO];
//[self.delegate didConnectedPeriph:dp];
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSInteger row = [self getRowForPeripheral:peripheral];
if(row != -1)
{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:1];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
//ScanCell* cell = (ScanCell*)[self.tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = [[NSString alloc] initWithFormat:#""];
cell.accessoryType = UITableViewCellAccessoryNone;
//[cell.activityView stopAnimating];
DiscoveredPeripheral* dp = [discoveredPeripherals objectAtIndex:row];
dp.state = DP_STATE_IDLE;
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
bool new = TRUE;
DiscoveredPeripheral* discPeripheral;
int row = -1;
if((state == SCAN_S_APPEARED_SCANNING) &&
(peripheral != nil))
{
for(int i = 0; (i < discoveredPeripherals.count) && (new == TRUE); i++)
{
NSLog(#"Scan Ajout periph");
discPeripheral = [discoveredPeripherals objectAtIndex:i];
if(discPeripheral.peripheral == peripheral)
{
new = false;
row = i;
discPeripheral.peripheral = peripheral;
}
}
if(new == TRUE)
{
discPeripheral = [[DiscoveredPeripheral alloc] initWithPeripheral:peripheral andAdvertisment:advertisementData andRssi:RSSI];
discPeripheral.rssi = RSSI;
if(peripheral.isConnected == TRUE)
{
discPeripheral.state = DP_STATE_CONNECTED;
}
[discoveredPeripherals addObject:discPeripheral];
NSLog(#"Scan Ajout periph, total:%i",[discoveredPeripherals count]);
NSLog(#"Scan %i: Add %#",[discoveredPeripherals count]-1, discPeripheral.peripheral.name);
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[discoveredPeripherals count]-1 inSection:1];
NSLog(#"Scan Nouveau periph, index:%i, section:%i",indexPath.row,indexPath.section);
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = discPeripheral.peripheral.name;
//[self.tableView insertRowsAtIndexPaths: [NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
else
{
discPeripheral.peripheral = peripheral;
discPeripheral.advertisment = advertisementData;
discPeripheral.rssi = RSSI;
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:1];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
//ScanCell* cell = (ScanCell*)[self.tableView cellForRowAtIndexPath:indexPath];
//NSLog(#"%i: Update %#", row, discPeripheral.peripheral.name);
cell.textLabel.text = discPeripheral.peripheral.name;
//cell.labelInfo.text = [[NSString alloc] initWithFormat:#"RSSI: %#", discPeripheral.rssi];
}
}
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSInteger row = [self getRowForPeripheral:peripheral];
if(row != -1)
{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:1];
UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath:indexPath];
//ScanCell* cell = (ScanCell*)[self.tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.text = [[NSString alloc] initWithFormat:#""];
cell.accessoryType = UITableViewCellAccessoryNone;
//[cell.activityView stopAnimating];
DiscoveredPeripheral* dp = [discoveredPeripherals objectAtIndex:row];
dp.state = DP_STATE_IDLE;
}
}
- (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
{
//DiscoveredPeripheral* discPeripheral;
CBPeripheral* peripheral;
for(int i = 0; i < peripherals.count; i++)
{
peripheral = [peripherals objectAtIndex:i];
/*
discPeripheral = [[DiscoveredPeripheral alloc] initWithPeripheral:peripheral andAdvertisment:nil andRssi:nil];
if(peripheral.isConnected == TRUE)
{
discPeripheral.state = DP_STATE_CONNECTED;
}
[discoveredPeripherals addObject:discPeripheral];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[discoveredPeripherals count] - 1 inSection:1];
[self.tableView insertRowsAtIndexPaths: [NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
*/
//[cbCentralManager cancelPeripheralConnection:peripheral];
NSDictionary *dictionary;
dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];
[cbCentralManager connectPeripheral:peripheral options:dictionary];
}
}
- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
//NSLog(#"Central Manager State: %d", [central state]);
if(central.state == CBCentralManagerStatePoweredOn)
{
[cbCentralManager retrieveConnectedPeripherals];
}
}
#end
Edit:
This view is called from a view controller.
The view controller is receiving data from bluetooth, record and displays the data.
What I would like to achieve is to have a separate view to connect to the BLE peripheral, go back to the main view, attach the serial port and run.
In a second time, if the peripheral is lost, try to reconnect to it, else pop the connection view and alert the user.
Cheers.
Cedric
You need to retain the peripheral. As soon as the peripheral object you are passed is released, iOS drops the connection. Save the CBPeripheral object in a variable, and be sure to pass that back to your main view when the scan view closes.
A very nice way to manage your entire bluetooth processes is the singleton model. You can move all your bluetooth code to a separate NSObject class and declare that file as a singleton. Create a function within your singleton class to initiate the connectPeripheral after you discover your device. Whenever you connect, you can save the peripheral you are connecting to as a variable or in an array if you have multiple devices. It's quite simple once you get the hang of it. Using this method of implementation you can refer to your connected Peripheral from anywhere within your app. Hope this helped!