Button values appearing as "null" - ios

I'm trying to have two buttons in my SearchCategoryChooserViewcontroller to display titles based on values being returned by a function. However, the buttons seem to be showing up with "null" for a title, even though the topCategoriesArray is successfully being returned. Here's my setup:
SearchCategoryChooserViewController.m:
#import "SearchCategoryChooserViewController.h"
#import "SearchViewController.h"
#interface SearchCategoryChooserViewController ()
#end
#implementation SearchCategoryChooserViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *category1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
category1.frame = CGRectMake(10, 120, 300, 35);
[category1 setTitle: [NSString stringWithFormat:#"%#", self.topCategory1] forState:UIControlStateNormal];
[category1 addTarget:self action:#selector(myButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: category1];
UIButton *category2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
category2.frame = CGRectMake(10, 180, 300, 35);
[category2 setTitle: [NSString stringWithFormat:#"%#", self.topCategory2] forState:UIControlStateNormal];
[category2 addTarget:self action:#selector(myButtonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview: category2];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#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.
}
*/
#end
SearchCategoryChooserViewController.h:
#import <UIKit/UIKit.h>
#import "SearchViewController.h"
#interface SearchCategoryChooserViewController : SearchViewController
#end
SearchViewController.h:
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#import <Parse/PFCloud.h>
#import "CriteriaViewController.h"
#interface SearchViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIButton *nextButtonOutlet;
#property (weak, nonatomic) NSString *topCategory1;
#property (weak, nonatomic) NSString *topCategory2;
#end
SearchViewController.m:
#import "SearchViewController.h"
#interface SearchViewController ()
#property (weak, nonatomic) IBOutlet UITextField *itemSearch;
#property (weak, nonatomic) IBOutlet UIButton *nextButton;
#end
#implementation SearchViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.nextButtonOutlet addTarget:self action:#selector(nextButton:) forControlEvents:UIControlEventTouchUpInside];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)nextButton:(id)sender
{
if (self.itemSearch.text.length > 0) {
[PFCloud callFunctionInBackground:#"eBayCategorySearch"
withParameters:#{#"item": self.itemSearch.text}
block:^(NSDictionary *result, NSError *error) {
NSLog(#"'%#'", result);
NSArray *resultArray = [result objectForKey:#"results"];
NSDictionary *dictionary0 = [resultArray objectAtIndex:0];
NSNumber *numberOfTopCategories = [dictionary0 objectForKey:#"Number of top categories"];
NSDictionary *dictionary1 = [resultArray objectAtIndex:1];
NSNumber *topCategories = [dictionary1 objectForKey:#"Top categories"];
NSDictionary *dictionary2 = [resultArray objectAtIndex:2];
NSNumber *numberOfMatches = [dictionary2 objectForKey:#"Number of matches"];
NSDictionary *dictionary3 = [resultArray objectAtIndex:3];
NSNumber *userCategoriesThatMatchSearch = [dictionary3 objectForKey:#"User categories that match search"];
NSArray *topCategoriesArray = [dictionary1 objectForKey:#"Top categories"];
NSString *topCategory1 = [topCategoriesArray objectAtIndex:0];
NSString *topCategory2 = [topCategoriesArray objectAtIndex:1];
if (!error) {
// if 1 match found clear categoryResults and top2 array
if ([numberOfMatches intValue] == 1 ){
[self performSegueWithIdentifier:#"ShowMatchCenterSegue" sender:self];
}
// if 2 matches found
else if ([numberOfMatches intValue] == 2){
[self performSegueWithIdentifier:#"ShowUserCategoryChooserSegue" sender:self];
//default to selected categories criteria -> send to matchcenter -> clear categoryResults and top2 array
}
// if no matches found, and 1 top category is returned
else if ([numberOfMatches intValue] == 0 && [numberOfTopCategories intValue] == 1) {
[self performSegueWithIdentifier:#"ShowCriteriaSegue" sender:self];
}
// if no matches are found, and 2 top categories are returned
else if ([numberOfMatches intValue] == 0 && [numberOfTopCategories intValue] == 2) {
[self performSegueWithIdentifier:#"ShowSearchCategoryChooserSegue" sender:self];
}
}
}];
}
}
#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:#"ShowSearchCategoryChooserSegue"]){
// SearchCategoryChooserViewController *controller = (SearchCategoryChooserViewController *) segue.destinationViewController;
// controller.itemSearch.text = self.itemSearch.text;
// }
}
#end

There are multiple issues:
You should change the code:
#property (weak, nonatomic) NSString *topCategory1;
#property (weak, nonatomic) NSString *topCategory2;
to
#property (strong, nonatomic, copy) NSString *topCategory1;
#property (strong, nonatomic, copy) NSString *topCategory2;
or
//because strong is default
#property (nonatomic, copy) NSString *topCategory1;
#property (nonatomic, copy) NSString *topCategory2;
It is better if you add the ´copy´ attribute for the NSString properties in case of using NSMutableString value.
Because with ARC if there is not at least one strong reference for an object it will be deallocated. If your Object have only a weak reference to an another object, it is not own it and it will be deallocated even if you use it in your Object. But with strong reference your Object own the another Object and it will not be deallocated until your Object lives.
And you should be set the property values before perform a segue with change this code
NSString *topCategory1 = [topCategoriesArray objectAtIndex:0];
NSString *topCategory2 = [topCategoriesArray objectAtIndex:1];
to
self.topCategory1 = [topCategoriesArray objectAtIndex:0];
self.topCategory2 = [topCategoriesArray objectAtIndex:1];
and use the values in prepareForSegue:
if([segue.identifier isEqualToString:#"ShowSearchCategoryChooserSegue"]){
SearchCategoryChooserViewController *controller = (SearchCategoryChooserViewController *) segue.destinationViewController;
controller.itemSearch.text = self.itemSearch.text;
controller.topCategory1 = self.topCategory1;
controller.topCategory2 = self.topCategory1;
}

It appears to me (from the code you've pasted into your question) that you are never setting your "topCategory1" string property in your SearchCategoryChooserViewController object.
Which would explain why you are seeing "null" in the label.

Related

Add up all values in NSMutableArray and multiply by value depending on Plain Segmented Control

What i want to do is multiply the latest NSMutableArray array entry (entered using a UITextField) by 3 when Moderate intensity is selected using the Plain Segmented Control and 6 when vigorous is selected and then display the total value of all entries in the array after the multiplications have occurred. E.g. If there User selects Moderate using the Plain Segmented Control and enters 120 in the UITextField, I need a value of 360 to be displayed and for that value to increment as more entries are made.
So far I'm storing the array values in a table like below which works fine.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SecondViewControllerSegue"]) {
SecondViewController *secondViewController
= [segue destinationViewController];
//secondViewController.infoRequest = self.nameField.text;
NSString* style = (styleSeg.selectedSegmentIndex == 0) ? #"Moderate intensity for" : #"Vigourous intensity for";
[activities addObject:[[NSString alloc]initWithFormat:#"Your activity: %#", self.activityField.text]];
secondViewController.activities = activities;
[activities addObject:[[NSString alloc]initWithFormat:#"%#: %# minutes", style, self.nameField.text]];
secondViewController.activities = activities;
}
}
I just can't seem to multiply and output the values. I've been playing around with something like
if(styleseg.selectedSegmentIndex == 0){
3x(what the user entered in duration)
}
if(styleseg.selectedSegmentIndex == 1){
6x(what the user entered in duration)
}
And a loop attempting to add up the total values in the array which is just outputting 0.
int result = 0;
for(int i=0;i<[activities count];i++)
result += [[activities objectAtIndex:i] intValue];
NSLog(#"result = %d", result);
I'm just having trouble blending the two together to do what I want. Any help is greatly appreciated.
NEW EDIT
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
IBOutlet UIView *nameView;
IBOutlet UITextField *nameField;
IBOutlet UITextField *activityField;
IBOutlet UISegmentedControl *styleSeg;
}
#property UIView *nameView;
#property UITextField *nameField;
#property UITextField *activityField;
#property (strong,nonatomic) NSMutableArray *activities;
- (IBAction)submitButtonTapped:(id)sender;
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#import "MyActivity.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize nameView;
#synthesize nameField;
#synthesize activityField;
#synthesize activities;
- (void)viewDidLoad
{
[super viewDidLoad];
activities = [[NSMutableArray alloc] init];
//activityName = [[NSMutableArray alloc] init];
}
-(void)viewWillAppear:(BOOL)animated
{
self.nameField.text = #"";
self.activityField.text = #"";
styleSeg.selectedSegmentIndex = 0;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)submitButtonTapped:(id)sender {
NSLog(#"The submit button was clicked.");
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SecondViewControllerSegue"]) {
SecondViewController *secondViewController
= [segue destinationViewController];
secondViewController.infoRequest = self.nameField.text;
/* This was my initial code as in the intial question
NSString* style = (styleSeg.selectedSegmentIndex == 0) ? #"Moderate intensity for" : #"Vigourous intensity for";
[activities addObject:[[NSString alloc]initWithFormat:#"Your activity: %#", self.activityField.text]];
secondViewController.activities = activities;
[activities addObject:[[NSString alloc]initWithFormat:#"%#: %# minutes", style, self.nameField.text]];
secondViewController.activities = activities;
*/
// New code
MyActivity *activity=[[MyActivity alloc]init];
activity.description=self.activityField.text;
activity.duration=[self.nameField.text intValue];
activity.intensity=(styleSeg.selectedSegmentIndex == 0) ? 3:6;
[self.activities addObject:activity];
secondViewController.activities = activities;
}
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
IBOutlet UIView *secondView;
IBOutlet UILabel *nameLabel;
}
#property IBOutlet UITableView *activityTableView;
#property NSMutableArray* activities;
//#property NSMutableArray* activityName;
#property UIView *secondView;
#property UILabel *nameLabel;
#property (weak, nonatomic) IBOutlet UILabel *nameLabel2;
#property id infoRequest;
-(IBAction)goBack:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize secondView;
#synthesize nameLabel;
#synthesize nameLabel2;
#synthesize activities;
#synthesize infoRequest;
#synthesize activityTableView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.nameLabel.text = [self.infoRequest description];
self.nameLabel2.text = [self.infoRequest description];
// activities = [[NSArray alloc] init];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)goBack:(id)sender
{
UINavigationController* parent = (UINavigationController*)[self parentViewController];
[parent popViewControllerAnimated:YES];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Number of rows is the number of time zones in the region for the specified section.
return [activities count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellReuseIdentifier = #"CellReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
}
NSString* s = [activities objectAtIndex:indexPath.row];
cell.textLabel.text = s;
return cell;
}
Your array seems to hold arbitrary strings, not integers represented as strings (the intValue of "10" is 10, but the intValue of "Moderate intensity for: 10 minutes" is 0). Also you are adding multiple elements for each instance of an activity - the activity description and the activity duration.
I would create another object class to encapsulate the activity -
MyActivity.h
#interface MyActivity : NSObject
#property (copy,nonatomic) NSString *description;
#property int duration;
#property int intensity;
#end
Create a UIButton and set it's touch up inside event to doAddToArray. This will add an entry to the array for each new activate. Allocate a new MyActivity and set the appropriate properties before adding it to the array -
In ViewController.m
-(IBAction)doAddToArray:(id)sender {
MyActivity *activity=[[MyActivity alloc]init];
activity.description=self.activityField.text;
activity.duration=[self.nameField.text intValue];
activity.intensity=(styleSeg.selectedSegmentIndex == 0) ? 3:6;
[self.activities addObject:activity];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SecondViewControllerSegue"]) {
SecondViewController *secondViewController
= [segue destinationViewController];
secondViewController.activities = activities;
}
Then in SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
IBOutlet UIView *secondView;
IBOutlet UILabel *nameLabel;
}
#property IBOutlet UITableView *activityTableView;
#property UIView *secondView;
#property UILabel *nameLabel;
#property (weak, nonatomic) IBOutlet UILabel *nameLabel2;
#property (weak, nonatomic) NSArray *activities; // This is used to provide content to the UITableView
#property id infoRequest;
-(IBAction)goBack:(id)sender;
#end
For brevity I won't include the full SecondViewController.m, but you have a number of places where you use activities that should be self.activities
Then to total the array (wherever you need to)-
int total=0;
for (MyActivity *activity in self.activities)
{
total+=activity.duration*activity.intensity;
}

Pass info to multiple viewControllers via iCarousel

I'm trying to implement an iCarousel that will pass information on to two other view controllers when an image is chosen. While the iCarousel loads perfectly and transitions to the next VC, the information is not displayed on the new VC.
The approach I chose was to create an NSObject file. I can't simply pass the info from VC to VC since I have several VC's that need the information and I'd prefer not to create a singleton or use AppDelegate if possible.
FYI: I do have a tap gesture recognizer added on top of the UIView that acts as the segue to the next VC if that makes any difference.
I've tried every possible tutorial out there and can't seem to figure out my problem. I just need to display a text label and a picture, which should really be pretty easy. Can someone take a quick glance at my code to see what I'm doing wrong?
My NSObject File:
#import <Foundation/Foundation.h>
#interface Stop : NSObject
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *image;
#end
First ViewController.h (with iCarousel on it):
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import "iCarousel.h"
#import "DirectionsViewController.h"
#import "Stop.h"
#interface StopsMenuViewController : UIViewController <iCarouselDataSource, iCarouselDelegate>
#property (strong, nonatomic) IBOutlet iCarousel *carousel;
#property (strong, nonatomic) IBOutlet UILabel *titleLabel;
//Title
#property (nonatomic, strong) NSArray *stopTitles;
#property (nonatomic, strong) NSString *stopChosen;
//Image
#property (nonatomic, strong) NSArray *stopImages;
#property (nonatomic, strong) NSString *imageChosen;
#end
First ViewController.m:
#import "StopsMenuViewController.h"
#interface StopsMenuViewController () {
NSMutableArray *allInfo; }
#end
#implementation StopsMenuViewController
#synthesize titleLabel, carousel, stopImages, stopTitles, stopChosen, imageChosen;
- (void)awakeFromNib {
NSString *myPlist = [[NSBundle mainBundle] pathForResource:#"Chinatown" ofType:#"plist"];
NSDictionary *rootDictionary = [[NSDictionary alloc] initWithContentsOfFile:myPlist];
self.stopImages = [rootDictionary objectForKey:#"StopImages"];
self.stopTitles = [rootDictionary objectForKey:#"StopTitles"];
}
- (void)carouselDidScroll:(iCarousel *)carousel {
[titleLabel setText:[NSString stringWithFormat:#"%#", [self.stopTitles
objectAtIndex:self.carousel.currentItemIndex]]];
}
- (void)dealloc {
self.carousel.delegate = nil;
self.carousel.dataSource = nil;
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"toDirections"])
{
DirectionsViewController *dvc = [segue destinationViewController];
int itemId = [self.carousel currentItemIndex];
NSIndexPath *path = [NSIndexPath indexPathForRow:itemId inSection:0];
Stop *current = [allInfo objectAtIndex:path.row];
[dvc setPassInfo:current];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
self.carousel.type = iCarouselTypeCoverFlow2;
allInfo = [[NSMutableArray alloc] init];
Stop *info = [[Stop alloc] init];
stopChosen = [NSString stringWithFormat:#"%#", [self.stopTitles objectAtIndex:self.carousel.currentItemIndex]];
[info setTitle:stopChosen];
[allInfo addObject:info];
info = [[Stop alloc] init];
self.imageChosen = [NSString stringWithFormat:#"%#", [self.stopImages
objectAtIndex:self.carousel.currentItemIndex]];
[info setTitle:self.imageChosen];
[allInfo addObject:info];
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.carousel = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel {
return [self.stopImages count];
}
- (NSUInteger)numberOfVisibleItemsInCarousel:(iCarousel *)carousel {
return 4;
}
- (UIView *)carousel:(iCarousel *)_carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view {
if (view == nil)
{
view = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.stopImages objectAtIndex:index]]];
}
return view;
}
- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index {
DirectionsViewController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"dvc"];
[self.navigationController pushViewController:dvc animated:YES];
}
#end
Second ViewController.h:
#import <UIKit/UIKit.h>
#import "Stop.h"
#interface DirectionsViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *titleLabel;
#property (strong, nonatomic) IBOutlet UIImageView *imageBox;
#property (nonatomic, strong) Stop *PassInfo;
#property (nonatomic, strong) NSString *stopTitle;
#property (nonatomic, strong) NSString *myStopTitle;
#end
Second ViewController.m:
#import "DirectionsViewController.h"
#interface DirectionsViewController ()
#end
#implementation DirectionsViewController
#synthesize PassInfo;
- (void)viewDidLoad {
[super viewDidLoad];
[self.titleLabel setText:[PassInfo title]];
UIImage *image = [UIImage imageNamed:[PassInfo image]];
[self.imageBox setImage:image];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Instead of
- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index {
DirectionsViewController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"dvc"];
[self.navigationController pushViewController:dvc animated:YES];
}
Use
- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index {
[self performSegueWithIdentifier:#"toDirections" sender:self];
}
In your code, you're instantiating the second view controller and presenting it, which is not the same as performing a segue. Therefore the method - prepareForSegue:sender: will not be invoked.

Add a push segue to a button inside of a custom cell of a tableview

I have a project that displays a feed of statuses similar to other social networks. Each feed item has several button that do different things. 1 of the buttons opens a new viewcontroller that displays the comments that have been posted on a particular status. When this button is clicked and the view controller is opened i would like it to be a push segue so that their is a back button and the user can navigate back to the feed.
When this button is clicked and the new vc is launched some unique data about the particular status/cell being clicked needs to be sent to the "comments vc ". Where would the code for doing this go?
CUSTOM CELL .H
#import <UIKit/UIKit.h>
#interface FeedItemCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *DefaultImg;
#property (weak, nonatomic) IBOutlet UILabel *NameLabel;
#property (weak, nonatomic) IBOutlet UILabel *StatusLabel;
#property (weak, nonatomic) IBOutlet UILabel *timeLabel;
#property (nonatomic, copy) NSString *msg_id;
#property (nonatomic, copy) NSString *status;
#property (nonatomic, weak) IBOutlet UIButton* commentButton;
#property (nonatomic, weak) IBOutlet UIButton* bumpButton;
#property (strong, nonatomic) id delegate;
-(IBAction)viewComments:(id)sender;
-(IBAction)bump:(id)sender;
#end
#protocol CustomCellProtocol <NSObject>
- (void)EBCellPressed:(NSString *)cellName;
CUSTOM CELL .M
#import "FeedItemCell.h"
#import "CommentsViewController.h"
#import "NSDate+TimeAgo.h"
#interface FeedItemCell() <WYPopoverControllerDelegate>
{
}
- (IBAction)open:(id)sender;
- (void)close:(id)sender;
#end
#implementation FeedItemCell
#synthesize commentButton;
- (instancetype)initWithDelegate:(id)delegate {
self = [super init];
if (self) {
self.delegate = delegate;
// Initialization code
}
return self;
}
-(IBAction)bump:(id)sender{
[self.delegate EBCellPressed:#"NAME"];
}
- (IBAction)open:(id)sender
{
}
#end
publicFeed . M
#import "PublicFeedViewController.h"
#import "FeedItemCell.h"
#import "AFNetworking.h"
#import "UIImageView+WebCache.h"
#import "InboxDetailViewController.h"
#import "SWRevealViewController.h"
#import "CommentsViewController.h"
#import "NSDate+TimeAgo.h"
#interface PublicFeedViewController (){
NSArray *NameLabel;
NSArray *StatusLabel;
NSMutableArray *feedArray;
}
#end
#implementation PublicFeedViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//The below code prompts the user for push notifications. If allowed, code in AppDelegate takes over and stores the token.
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
// Do any additional setup after loading the view.
self.FeedTable.dataSource=self;
self.FeedTable.delegate=self;
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"foo": #"bar"};
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
[manager POST:#"www" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
//NSLog(#"JSON: %#", responseObject);
self->feedArray = [responseObject objectForKey:#"feed"];
[self.FeedTable reloadData];
[UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return feedArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier=#"Cell";
FeedItemCell *Cell=[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!Cell){
Cell = [[FeedItemCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSLog(#"FEED ARRAY: %#", self->feedArray);
NSDictionary *tempDictionary= [self->feedArray objectAtIndex:indexPath.row];
// Display recipe in the table cell
NSString *thumb_img = [tempDictionary objectForKey:#"thumb_img"];
NSString *thumb_path=#"http://buhzhyve.com/CI_REST_LOGIN/UPLOADS/thumbs/";
NSString *thumb_url = [thumb_path stringByAppendingString:thumb_img];
Cell.NameLabel.text=[tempDictionary objectForKey:#"first_name"];
Cell.StatusLabel.text=[tempDictionary objectForKey:#"message"];
Cell.msg_id=[tempDictionary objectForKey:#"msg_id"];
//Cell.status=[tempDictionary objectForKey:#"message"];
Cell.StatusLabel.lineBreakMode=0;
Cell.StatusLabel.numberOfLines=0;
NSString *commentCount = [tempDictionary objectForKey:#"comment_count"];
NSString *commentButtonText =[NSString stringWithFormat:#"Comments ( %# )",commentCount];
[Cell.commentButton setTitle:commentButtonText forState: UIControlStateNormal];
NSString *bumpCount = [tempDictionary objectForKey:#"bump_count"];
NSString *bumpButtonText =[NSString stringWithFormat:#"Bumps ( %# )",bumpCount];
[Cell.bumpButton setTitle:bumpButtonText forState: UIControlStateNormal];
//[Cell.StatusLabel sizeToFit];
NSString *created_string=[tempDictionary objectForKey:#"created"];
double created_double = created_string.doubleValue;
NSDate *date = [[NSDate alloc] initWithTimeIntervalSince1970:created_double];
NSString *ago = [date timeAgo];
Cell.timeLabel.text=ago;
//Cell.DefaultImg.image = [UIImage imageNamed:#"buhz_mini_logo.png"];
[Cell.DefaultImg setImageWithURL:[NSURL URLWithString:thumb_url]
placeholderImage:[UIImage imageNamed:#"buhz_mini_logo.png"]];
return Cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Ideally you should do lazy loading so that instead of creating a new textView each time, you just reuse the same one.
UITextView *temp = [[UITextView alloc] initWithFrame:CGRectMake(82, 26, self.FeedTable.frame.size.width, 18)]; //This initial size doesn't matter
NSDictionary *tempDictionary= [self->feedArray objectAtIndex:indexPath.row];
NSString *status = [tempDictionary objectForKey:#"message"];
temp.font =[UIFont fontWithName:#"System" size:12];
temp.text = status;
CGFloat textViewWidth = 218;
CGRect tempFrame = CGRectMake(82,26,textViewWidth,18); //The height of this frame doesn't matter.
CGSize tvsize = [temp sizeThatFits:CGSizeMake(tempFrame.size.width, tempFrame.size.height)]; //This calculates the necessary size so that all the text fits in the necessary width.
//Add the height of the other UI elements inside your cell
return tvsize.height + 70;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"commentSegue"]) {
}
}
#end
publicfeed .h
#import <UIKit/UIKit.h>
#interface PublicFeedViewController : UIViewController<UITableViewDataSource,UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UITableView *FeedTable;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton;
- (IBAction)addItem;
#end
So assuming that you're creating this button in code, this is how you could handle this.
This first line tells the button that when it's pressed, it needs to call this specific selector/method sent as the action.
[button addTarget:self action:#selector(showNextViewController) forControlEvents:UIControlEventTouchUpInside];
Then you would create this method in the same class.
- (void) showNextViewController
{
NewViewController *newViewController = [[NewViewController alloc] init]; //Edit this line of course to fit for your situation. I'm not sure if you're loading from an XIB or from a Storyboard, or neither.
newViewController.someVariable = someVariable;
newViewController.someOtherVariable = someOtherVariable;
[[[[[UIApplication sharedApplication] delegate] window] rootViewController].navigationController pushViewController:view animated:YES];
}
This will send the necessary data to the new view controller, and it will also display the new view on the screen with a back button.
Hope this works!
1. Ok so lets pretend this is your custom cell class.
in your .h file of the custom cell you need to add a protocol.
#import <UIKit/UIKit.h>
#interface CustomCell : UIView
#property (strong, nonatomic) id delegate; //this is used for sending messages out of the custom cell
//init
- (id)initWithFrame:(CGRect)frame andCatName:(NSString *)name andDelegate:(id)delegate;
#end
#protocol CustomCellProtocol <NSObject>
-(void)customCellSelected:(NSString *)cellName;
#end
what we actually did is something like creating a custom event that the class can throw out and everyone who subscribes to that can run a method when customCellSelected is thrown.
2. now when you create each custom cell with the init method you need to provide a delegate which kind of points to which class should the custom cell transfer the call to customCellSelected so in the init method you set that delegate.
- (id)initWithFrame:(CGRect)frame andDelegate:(id)delegate {
self = [super initWithFrame:frame];
if (self) {
self.delegate = delegate; //setting which class should be called when calling protocol methods.
// Your initialization code
}
return self;
}
3. now in your .m file of the custom cell, when the user presses your button and you enter your method , let it be buttonPressed
- (IBAction) buttonPressed:(id)sender {
[self.delegate customCellSelected:#"THE CELL'S NAME"]; // calling the protocol method.
}
now the call to the delegate method should be transferred to the vc because when you create the custom cell you use initWithFrame:(CGRect)frame andDelegate:(id)delegate and you transfer self as the delegate , so when [self.delegate customCellSelected:#"THE CELL'S NAME"]; is called it is actually called on the vc.
4. this is how you create the custom cell in the vc:
customCell *tempView = [[customCell alloc] initWithFrame:CGRectMake(X, Y, Width, Height) andDelegate:self]; // here you set the vc as the delegate
5.and now all you have to do is add the method customCellSelected to your vc code so it can called when the customCell is calling it.
- (void)customCellSelected:(NSString *)cellName {
self.selectedCell = cellName;
[self performSegueWithIdentifier:#"SelectedCell" sender:self];
}
6.then add this in the vc:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"SelectedCell"]) {
LevelSelectViewController *levelSelectViewController = (LevelSelectViewController *)segue.destinationViewController;
levelSelectViewController.cellName = self.selectedCell;
}
}
7.only thing you have to remember is to create a segue from your first vc to the second like this:

AddRecord TableView controller -->MasterTableView Controller --> second (filter) TableView Controller --> DetailView Controller

I'm new to iOS programing (and programming in general). I'm trying to do an iPhone App based on the Birdsighting example provided by Apple (http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/SecondiOSAppTutorial/Introduction/Introduction.html). The difference is that I will create Body Building's workouts (instead of Birdsightings) in an AddWorkout TableView Controller, pass the workout to the Master TableView Controller and from there being able, by selecting a workout's cell, to display a second TableView Controller similar to the Master's one, that shows events of that workout sorted by muscle bands; then, selecting a muscle band cell, pushing a DetailView Controller with all relative parameters of that muscle band's workout (exercise type, weight, series number....). All this is embedded in a navigation controller.
The problem is that I can't pass a new record on the second TableView Controller (MuscleBandViewController) and therefore I can't neither push it to the detailViewController. Any suggestion? I'm stuck for a week 'til now (sorry for my bad English: I'm Italian).
Here is my DataController.h code:
#import <Foundation/Foundation.h>
#class Workouts;
#interface IFitDataController : NSObject
#property (nonatomic, copy)NSMutableArray *masterWorkoutsList;
#property (nonatomic, copy)NSMutableArray *masterMuscleBandList;
- (NSUInteger)countOfList;
- (NSUInteger)countOfMuscleBandList;
- (Workouts *)objectInListAtIndex:(NSUInteger)theIndex;
- (Workouts *)objectInMasterMuscleBandListAtIndex:(NSUInteger)index;
- (void)addWorkoutsWithWorkouts:(Workouts *)thisWorkout;
#end
Here DataController.m:
#import "IFitDataController.h"
#import "Workouts.h"
#interface IFitDataController ()
- (void)initializeDefaultDataList;
#end
#interface IFitDataController ()
- (void)initializeMuscleBandDataList;
#end
#implementation IFitDataController
- (void)initializeDefaultDataList {
NSMutableArray *workoutsList = [[NSMutableArray alloc] init];
self.masterWorkoutsList = workoutsList;
Workouts *thisWorkout;
NSDate *today = [NSDate date];
thisWorkout = [[Workouts alloc] initWithName:#"Pectorals" exercise:#"Pectoral Machine" series:#"3" nActionsInSerie:#"10" measure:#"Kg" weight:#"25" date:today comment:#"Add your comment"];
[self addWorkoutsWithWorkouts:thisWorkout];
}
- (void)setMasterWorkoutsList:(NSMutableArray *)newList {
if (_masterWorkoutsList != newList) {
_masterWorkoutsList = [newList mutableCopy];
}
}
- (void)initializeMuscleBandDataList {
NSMutableArray *muscleBandList = [[NSMutableArray alloc]init];
self.masterMuscleBandList = muscleBandList;
Workouts *thisWorkout;
NSDate *today = [NSDate date];
thisWorkout = [[Workouts alloc] initWithName:#"Pectorals" exercise:#"Pectoral Machine" series:#"3" nActionsInSerie:#"10" measure:#"Kg" weight:#"25" date:today comment:#"Add your comment"];
[self addWorkoutsWithWorkouts:thisWorkout];
}
- (void)setMasterMuscleBandList:(NSMutableArray *)newMuscleBandList {
if ((_masterMuscleBandList != newMuscleBandList)) {
_masterMuscleBandList = [newMuscleBandList mutableCopy];
}
}
- (id)init {
if (self = [super init]) {
[self initializeDefaultDataList];
[self initializeMuscleBandDataList];
return self;
}
return nil;
}
- (NSUInteger)countOfList {
return [self.masterWorkoutsList count];
}
- (NSUInteger)countOfMuscleBandList {
return [self.masterMuscleBandList count];
}
- (Workouts *)objectInListAtIndex:(NSUInteger)theIndex {
return [self.masterWorkoutsList objectAtIndex:theIndex];
}
- (Workouts *)objectInMasterMuscleBandListAtIndex:(NSUInteger)index {
return [self.masterMuscleBandList objectAtIndex:index];
}
- (void)addWorkoutsWithWorkouts:(Workouts *)thisWorkout {
[self.masterWorkoutsList addObject:thisWorkout];
[self.masterMuscleBandList addObject:thisWorkout];
}
#end
Here my AddWorkoutViewController.h:
#import <UIKit/UIKit.h>
#define muscleBandComponent 0
#define exercisesComponent 1
#class Workouts;
#interface AddWorkoutViewController : UITableViewController <UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UIPickerView *exercisePicker;
IBOutlet UITextView *commentInserted;
NSArray *_exercisesForPicker;
NSArray *_muscleBandForPicker;
NSDictionary *totalExercises;
}
#property (weak, nonatomic) IBOutlet UITextField *muscleBandName;
#property (weak, nonatomic) IBOutlet UITextField *exerciseName;
#property (weak, nonatomic) IBOutlet UILabel *nSeries;
#property (weak, nonatomic) IBOutlet UILabel *measureType;
#property (weak, nonatomic) IBOutlet UILabel *nActionsInSerie;
#property (weak, nonatomic) IBOutlet UILabel *weightPerformed;
#property (strong, nonatomic) IBOutlet UITextView *commentInserted;
#property (retain, nonatomic) IBOutlet UIPickerView *exercisePicker;
#property (retain, nonatomic) NSArray *muscleBandForPicker;
#property (retain, nonatomic) NSDictionary *totalExercises;
#property (retain, nonatomic) NSArray *exercisesForPicker;
- (IBAction)nSeriesStepper:(id)sender;
- (IBAction)nActionsSerieStepper:(id)sender;
- (IBAction)weightStepper:(id)sender;
- (void) closeKeyboard;
#property (strong, nonatomic) Workouts *workout;
#end
Here my AddWorkoutViewController.m:
#import "AddWorkoutViewController.h"
#import "Workouts.h"
#import "IFitDataController.h"
#interface AddWorkoutViewController ()
#end
#implementation AddWorkoutViewController
#synthesize exercisePicker;
#synthesize totalExercises;
#synthesize exercisesForPicker;
#synthesize muscleBandForPicker;
#synthesize nSeries;
#synthesize nActionsInSerie;
#synthesize weightPerformed;
#synthesize commentInserted;
- (IBAction)nSeriesStepper:(id)sender {
self.nSeries.text = [NSString stringWithFormat:#"%d", [[NSNumber numberWithDouble:[(UIStepper *)sender value]] intValue]];
}
- (IBAction)nActionsSerieStepper:(id)sender {
self.nActionsInSerie.text = [NSString stringWithFormat:#"%d", [[NSNumber numberWithDouble:[(UIStepper *)sender value]] intValue]];
}
- (IBAction)weightStepper:(id)sender {
self.weightPerformed.text = [NSString stringWithFormat:#"%d", [[NSNumber numberWithDouble:[(UIStepper *)sender value]] intValue]];
}
- (IBAction) go:(id)sender
{
[self closeKeyboard];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ReturnInput"]) {
if ([self.exerciseName.text length] || [self.muscleBandName.text length]) {
Workouts *thisWorkout;
NSDate *today = [NSDate date];
thisWorkout = [[Workouts alloc] initWithName:self.muscleBandName.text exercise:self.exerciseName.text series:self.nSeries.text nActionsInSerie:self.nActionsInSerie.text measure:self.measureType.text weight:self.weightPerformed.text date:today comment:self.commentInserted.text];
self.workout = thisWorkout;
}
}
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ((textField == self.exerciseName) || (textField == self.muscleBandName)) {
[textField resignFirstResponder];
}
return YES;
}
- (void) closeKeyboard
{
if([commentInserted isFirstResponder])
{
[commentInserted resignFirstResponder];
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Initialization code
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"muscleBands" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.totalExercises = dictionary;
NSArray *components = [self.totalExercises allKeys];
NSArray *sorted = [components sortedArrayUsingSelector:#selector(compare:)];
self.muscleBandForPicker = sorted;
NSString *selectedMuscleBand = [self.muscleBandForPicker objectAtIndex:0];
NSArray *array = [totalExercises objectForKey:selectedMuscleBand];
self.exercisesForPicker = array;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 2;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (component == muscleBandComponent)
return [self.muscleBandForPicker count];
return [self.exercisesForPicker count];
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (component == muscleBandComponent)
return [self.muscleBandForPicker objectAtIndex:row];
return [self.exercisesForPicker objectAtIndex:row];
}
-(void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
if (component == muscleBandComponent) {
NSString *selectedMuscleBand = [self.muscleBandForPicker objectAtIndex:row];
NSArray *array = [totalExercises objectForKey:selectedMuscleBand];
self.exercisesForPicker = array;
[exercisePicker selectRow:0 inComponent:exercisesComponent animated:YES];
[exercisePicker reloadComponent:exercisesComponent];
self.muscleBandName.text = [muscleBandForPicker objectAtIndex:row];
return;
}
self.exerciseName.text = [exercisesForPicker objectAtIndex:row];
}
#end
Here my MasterViewController.h:
#import <UIKit/UIKit.h>
#class IFitDataController;
#class Workouts;
#interface IFitMasterViewController : UITableViewController
#property (strong, nonatomic) IFitDataController *dataController;
#property (strong, nonatomic) IFitDataController *muscleBandDataController;
#property (strong, nonatomic) Workouts *thisWorkout;
- (IBAction)done:(UIStoryboardSegue *)segue;
- (IBAction)cancel:(UIStoryboardSegue *)segue;
#end
Here MasterViewController.m::
#import "IFitMasterViewController.h"
#import "IFitDetailViewController.h"
#import "IFitDataController.h"
#import "Workouts.h"
#import "AddWorkoutViewController.h"
#import "IFitMuscleBandViewController.h"
#implementation IFitMasterViewController
- (IBAction)done:(UIStoryboardSegue *)segue {
if ([[segue identifier] isEqualToString:#"ReturnInput"]) {
AddWorkoutViewController *addController = [segue sourceViewController];
if (addController.workout) {
[self.dataController addWorkoutsWithWorkouts:addController.workout];
[[self tableView] reloadData];
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
- (IBAction)cancel:(UIStoryboardSegue *)segue
{
if ([[segue identifier] isEqualToString:#"CancelInput"]) {
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
- (void)awakeFromNib
{
[super awakeFromNib];
self.dataController = [[IFitDataController alloc]init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dataController countOfList];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"WorkoutCell";
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc]init];
[formatter setDateStyle:NSDateFormatterFullStyle];
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Workouts *workoutAtIndex = [self.dataController objectInListAtIndex:indexPath.row];
[[cell textLabel]setText:[formatter stringFromDate:(NSDate *)workoutAtIndex.date]];
[[cell detailTextLabel]setText:workoutAtIndex.comment];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return NO;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowMuscleBandList"]) {
IFitMasterViewController *muscleBandViewController = [segue destinationViewController];
muscleBandViewController.thisWorkout = [self.muscleBandDataController objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
#end
Here MuscleBandViewController.h:
#import <UIKit/UIKit.h>
#class IFitDataController;
#interface IFitMuscleBandViewController : UITableViewController
#property (strong, nonatomic) Workouts *thisWorkout;
#property (strong, nonatomic) IFitDataController *dataController;
#property (strong, nonatomic) IFitDataController *muscleBandDataController;
#end
Here MuscleBandViewController.m:
#import "IFitMasterViewController.h"
#import "IFitDetailViewController.h"
#import "IFitDataController.h"
#import "Workouts.h"
#import "AddWorkoutViewController.h"
#import "IFitMuscleBandViewController.h"
#class IFitDataController;
#implementation IFitMuscleBandViewController
- (void)awakeFromNib
{
[super awakeFromNib];
self.muscleBandDataController = [[IFitDataController alloc]init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.muscleBandDataController countOfMuscleBandList];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MuscleBandCell";
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc]init];
[formatter setDateStyle:NSDateFormatterFullStyle];
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Workouts *workoutAtIndex = [self.muscleBandDataController objectInMasterMuscleBandListAtIndex:indexPath.row];
[[cell textLabel]setText:workoutAtIndex.muscleBand];
[[cell detailTextLabel]setText:workoutAtIndex.comment];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowWorkoutDetails"]) {
IFitDetailViewController *detailViewController = [segue destinationViewController];
detailViewController.thisWorkout = [self.muscleBandDataController objectInMasterMuscleBandListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
#end
Here DetailViewController.h:
#import <UIKit/UIKit.h>
#class Workouts;
#interface IFitDetailViewController : UITableViewController
#property (strong, nonatomic) Workouts *thisWorkout;
#property (weak, nonatomic) IBOutlet UILabel *muscleBandLabel;
#property (weak, nonatomic) IBOutlet UILabel *exerciseLabel;
#property (weak, nonatomic) IBOutlet UILabel *seriesLabel;
#property (weak, nonatomic) IBOutlet UILabel *nActionsInSerieLabel;
#property (weak, nonatomic) IBOutlet UILabel *measureLabel;
#property (weak, nonatomic) IBOutlet UILabel *weightLabel;
#property (weak, nonatomic) IBOutlet UILabel *dateLabel;
#property (weak, nonatomic) IBOutlet UILabel *commentLabel;
#end
and finally my DetailViewController.m:
#import "IFitDetailViewController.h"
#import "Workouts.h"
#interface IFitDetailViewController ()
- (void)configureView;
#end
#implementation IFitDetailViewController
#pragma mark - Managing the detail item
- (void)setWorkout:(Workouts *)newWorkout
{
if (_thisWorkout != newWorkout) {
_thisWorkout = newWorkout;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
Workouts *theWorkout = self.thisWorkout;
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc]init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
}
if (theWorkout) {
self.muscleBandLabel.text = theWorkout.muscleBand;
self.exerciseLabel.text = theWorkout.exercise;
self.seriesLabel.text = theWorkout.series;
self.nActionsInSerieLabel.text = theWorkout.nActionsInSerie;
self.measureLabel.text = theWorkout.measure;
self.weightLabel.text = theWorkout.weight;
self.title = [formatter stringFromDate:(NSDate *)theWorkout.date];
self.commentLabel.text = theWorkout.comment;
}
}
- (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

dynamically generated UIButton in iOS 5 ARC causes deallocated instance crash

I have a a class I created to generate UIButton's I add to my UIView. This worked great until my conversion to ARC yesterday, not I get the following error:
-[OrderTypeButton performSelector:withObject:withObject:]: message sent to deallocated instance 0x12449f70
Here is the code to add the button to my UIView (actually a subview in my main UIView):
OrderTypeButton *btn = [[OrderTypeButton alloc]initWithOrderType:#"All Orders" withOrderCount:[NSString stringWithFormat:#"%i",[self.ordersPlacedList count]] hasOpenOrder:NO];
btn.view.tag = 6969;
btn.delegate = self;
[btn.view setFrame:CGRectMake((col * width)+ colspacer, rowHeight + (row * height), frameWidth, frameHeight)];
[self.statsView addSubview:btn.view];
And here is my class header:
#import <UIKit/UIKit.h>
#protocol OrderTypeButtonDelegate
-(void) tapped:(id)sender withOrderType:(NSString*) orderType;
#end
#interface OrderTypeButton : UIViewController {
id<OrderTypeButtonDelegate> __unsafe_unretained delegate;
IBOutlet UILabel *lblOrderType;
IBOutlet UILabel *lblOrderCount;
NSString *orderType;
NSString *orderCount;
BOOL hasOpenOrder;
}
#property (nonatomic, strong) IBOutlet UIButton *orderButton;
#property (nonatomic, strong) IBOutlet UILabel *lblOrderType;
#property (nonatomic, strong) IBOutlet UILabel *lblOrderCount;
#property (nonatomic, strong) NSString *orderType;
#property (nonatomic, strong) NSString *orderCount;
#property (nonatomic, assign) BOOL hasOpenOrder;
#property (nonatomic, unsafe_unretained) id<OrderTypeButtonDelegate> delegate;
-(id) initWithOrderType: (NSString *) anOrderType withOrderCount: (NSString *) anOrderCount hasOpenOrder: (BOOL) openOrder;
-(IBAction)btnTapped:(id)sender;
#end
Implementation:
#import "OrderTypeButton.h"
#implementation OrderTypeButton
#synthesize orderButton;
#synthesize lblOrderType, lblOrderCount, orderType, orderCount, hasOpenOrder, delegate;
-(id) initWithOrderType: (NSString *) anOrderType withOrderCount: (NSString *) anOrderCount hasOpenOrder: (BOOL) openOrder {
if ((self = [super init])) {
self.orderType = anOrderType;
self.orderCount = anOrderCount;
self.hasOpenOrder = openOrder;
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.lblOrderType.text =[NSString stringWithFormat:#"%#", self.orderType];
self.lblOrderCount.text = [NSString stringWithFormat:#"%#", self.orderCount];
if (self.hasOpenOrder) {
[self.orderButton setBackgroundImage:[UIImage imageNamed:#"background-order-btn-red.png"] forState:UIControlStateNormal];
self.lblOrderType.textColor = [UIColor whiteColor];
self.lblOrderCount.textColor = [UIColor whiteColor];
}
}
-(IBAction)btnTapped:(id)sender {
NSLog(#"TAPPED");
if ([self delegate] ) {
[delegate tapped:sender withOrderType:self.orderType];
}
}
- (void)viewDidUnload
{
[self setOrderButton:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
This seems fairly simple what I am doing here, not sure what changed with ARC that is causing me problems.
Maybe ARC autorelease created button, try to store created buttons in Array
//.h file
#property (nonatomic, strong) NSArray *buttonsArray
//.m file
#synthesize buttonsArray
...
- (void)viewDidLoad {
buttonsArray = [NSArray array];
...
OrderTypeButton *btn = [[OrderTypeButton alloc]initWithOrderType:#"All Orders"
withOrderCount:[NSString stringWithFormat:#"%i",[self.ordersPlacedList count]]
hasOpenOrder:NO];
btn.view.tag = 6969;
btn.delegate = self;
[btn.view setFrame:CGRectMake((col * width)+ colspacer, rowHeight + (row * height), frameWidth, frameHeight)];
[self.statsView addSubview:btn.view];
//Add button to array
[buttonsArray addObject:btn];
Also this approach will help if you want to change buttons, or remove some specific button from view

Resources