How to Share Methods Between Classes - objective-c

I want to set the text of a label to the text of a cell from a different class.
In my MasterViewController I have:
// SAVE TEXT OF SELECTED CELL
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cellString = cell.textLabel.text;
}
//SHARES VARIABLES BETWEEN CLASSES
- (ChemProjectMasterViewController*) sharedVariable
{
static ChemProjectMasterViewController *myVariable = nil;
if (myVariable == nil)
{
myVariable = [[[self class] alloc] init];
myVariable.sharedCellString = cellString;
}
return myVariable;
}
I also have this in the .h
#interface ChemProjectMasterViewController : UITableViewController
#property (nonatomic)NSString *cellString;
#property (nonatomic)NSString *sharedCellString;
+(ChemProjectMasterViewController*) sharedVariable;
#end
Now the class I want to access this method from is DetailViewController. In that I have:
detailDescriptionLabel.text = [ChemProjectMasterViewController sharedVariable].sharedCellString;
Where the detailDescriptionLabel is just a text label.
**
The program compiles fine but I have the label text set to change when I click a button. The app runs smooth until I hit the button which causes it to crash. The main goal is to set the label text in DetailViewController to the text of a cell from MasterViewController. Thank you for any help!

I am seeing few things.
First one, in .h you have declared as class method (+), while in .m it is instance (-).
Second one is #property (nonatomic)NSString *sharedCellString; which is unsafe unretained, make it strong.
And kindly let me know, if it works ?

Related

Not able to obtain correct indexPath.row value from objective C file in Swift file

File: ContactsViewController.m
In this file I am using the didSelectRowAtIndexPath method to push a new View Controller to show information about the name that was pressed on the Table View Controller. The View Controller that will be displaying the information about the name is being implemented in Swift. The part that I am referring to in this code is in the didSelectRowAtIndexPath method, line:
_myIndex = indexPath.row;
I believe indexPath.row should return the index of the name that was tapped in the Table View Controller.
#import "ContactsViewController.h"
#import "Contacts-Swift.h"
#interface ContactsViewController ()
#property (nonatomic, readwrite, strong) NSMutableArray* contacts;
#property (nonatomic, readwrite) NSInteger myIndex;
#end
#implementation ContactsViewController
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
/*NSArray *contactArray = #[#"Johnny Appleseed", #"Paul Bunyan", #"Calamity Jane"];
_contacts = [NSMutableArray arrayWithArray:contactArray];*/
/*Contact *c1 = [[Contact alloc] initWithName: #"Johnny"];
Contact *c2 = [[Contact alloc] initWithName: #"Paul Bunyan"];
Contact *c3 = [[Contact alloc] initWithName: #"Calamity Jane"];*/
// _contacts = [NSMutableArray arrayWithArray: #[c1, c2, c3]];
self.contacts = [NSMutableArray array];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.tableView registerClass: [UITableViewCell class]
forCellReuseIdentifier:#"UITableViewCell"];
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return self.contacts.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"UITableViewCell" forIndexPath:indexPath];
Contact *contact = self.contacts[indexPath.row];
cell.textLabel.text = contact.name;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ContactsViewController *viewController = [self.navigationController.storyboard instantiateViewControllerWithIdentifier:#"the"];
[self.navigationController pushViewController:viewController animated:YES];
_myIndex = indexPath.row;
}
File: ContactsViewController.h
This is the header file that I am using in order to have access to the objective C methods and variables when working in the swift file. (I am not very familiar with objective C so there is a strong possibility that this implementation is what is causing my problems).
#import <UIKit/UIKit.h>
#interface ContactsViewController : UITableViewController <UITableViewDelegate>
#property (nonatomic, readonly) NSInteger myIndex;
#property (nonatomic, readonly, strong) NSMutableArray* contacts;
#end
File: ExistingContactViewController.swift
In the ExistingContactViewController I am just trying to set the firstName label equal to the text that is present in the contacts array at indexPath.row (in the ContactsViewController.m file).
import UIKit
#objc class ExistingContactViewController: UIViewController {
var contactsObject = ContactsViewController()
#IBOutlet weak var firstName: UILabel!
#IBOutlet weak var lastName: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
print("\(contactsObject.myIndex)")
firstName.text = contactsObject.contacts[contactsObject.myIndex] as? String
}
When clicking names that are added to the Table View Controller the only index that is ever printed
print("\(contactsObject.myIndex)")
is 0. Which tells me that I am not capturing the index of the name that is tapped.
Image of myStoryboard The bottom most scene is the one that I am trying to change the First Name label to display the name of the cell that was tapped.
I have not yet been able change the title of this label when clicking on a cell. I have been able to implement this functionality when using just swift files (through watching numerous videos). I am sure that there is a key concept I am missing in the objective C files so any suggestions and/or pointers are much appreciated. If any additional details are needed let me know!
Thanks.
Seems that in your didSelectRowAtIndexPath: you are pushing a ContactsViewController to the navigation stack and if I understand correctly it should be instance of ExistingContactViewController. Also you should set the contactsObject property of the ExistingContactViewController before pushing it in the navigation stack (before viewDidLoad is executed) otherwise it's value will always be a new ContactsViewController which, probably, is causing the issue.
I hope this helps!

segue to a view from a tableview in different class

To explain the issue, I had ViewControllerA with a UITableView called commentTableView inside of it. and from commentTableView i would segue to ViewControllerB but I needed to add an addition UITableView called mentionedFriendTable to ViewControllerA. But once i did add mentionFriendTable I started to have issues with the tables that caused the app to crash.
Issue Im Having
I decided to place commentTableView into a different class called justCommentsTable which is a UITableViewController class and add that class to ViewController. I have to place commentTableView in a different class and not mentionFriendTable because mentionFriendTable needs to be in ViewControllerA. and after a couple of hours I finally got that to work. but now that segue I initially had to ViewControllerB does not work, and crashes saying
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<justCommentsTable: 0x21032160>) has no segue with identifier 'segueToViewControllerB'
My Storyboard
On my storyboard i have ViewControllerA with a tableView inside of it and i linked up the tableview to #property (strong, nonatomic) IBOutlet UITableView *commentTable;
in the code below I explain how commentTable becomes the tableview from justCommentsTable
I know I'm getting this crash because ViewControllerB is connected to ViewControllerA through MainStoryboard.storyboard and not justCommentsTable
My Question
Is there a way to still segue ViewControllerA to ViewControllerB and pass data from commentTableView which is in a different class.
I'm gonna go ahead and place whatever code I find relevant to the issue. Just tell me if im missing any crucial code.
ViewControllerA.h
#import "justCommentsTable.h"
#interface ViewControllerA : UIViewController<UITableViewDelegate, UITableViewDataSource>{
// in justCommentsTable.m I add this controller to the view
justCommentsTable *commentsController;
}
// this is the table that is link up in storyboard
#property (strong, nonatomic) IBOutlet UITableView *commentTable;
//this is my mentions table that needs to be in ViewControllerA
#property (nonatomic, strong) UITableView *mentionTableView;
#end
ViewControllerA.m
- (void)viewDidLoad
{
[super viewDidLoad];
**// i set up the mentionTable here**
self.mentionTableView.transform = transform;
self.mentionTableView.delegate = self;
self.mentionTableView.dataSource = self;
self.mentionTableView.tag = 1;
[self.view addSubview:self.mentionTableView];
**// i set up the commentTable here**
if (commentsController == nil) {
commentsController = [[justCommentsTable alloc] init];
}
[commentTable setDataSource:commentsController];
[commentTable setDelegate:commentsController];
[commentsController setHomeUserID:homeUserID];
[commentsController setGetEventHostIDforNotif:getEventHostIDforNotif];
[commentsController setGeteventIDfrSEgue:geteventIDfrSEgue];
[commentsController setGetEVENTNamefrSegue:getEVENTNamefrSegue];
**// i set commentsController to the Tableview in justCommentsTable class**
commentsController.view = commentsController.tableView;
}
justCommentsTable.h
#interface justCommentsTable : UITableViewController<UITableViewDelegate, UITableViewDataSource,UITextFieldDelegate,UITextViewDelegate>
#end
justCommentsTable.m
#implementation justCommentsTable
//buttonTag is used for a button on the customCells
int buttonTag;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"commentCell";
customCell *cell =(customCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[customCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *commmentDict = [CommentArray objectAtIndex:indexPath.row];
NSString *commentText = [commmentDict objectForKey:#"comment"];
cell.textLabel.text = commentText;
// i need a custom button on the cells for other reasons
[cell.cellButton addTarget:self action:#selector(showButtonIndex:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
-(void)showButtonIndex:(UIButton*)button{
buttonTag = button.tag;
/*
buttonTag gets set here, and used in the prepareForSegue method
to find out what row the button was on.
*/
[self performSegueWithIdentifier:#"segueToViewControllerB" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"segueToViewControllerB"]){
//segue to profile from image button
ViewControllerB *VCB = segue.destinationViewController;
NSDictionary *commentDic = [CommentArray objectAtIndex:buttonTag];
/*
buttonTag was used to select the objectAtIndex
*/
NSString *commentTitle = [commentDic objectForKey:#"comment_title"];
VCB.title = commentTitle;
}
}
I know where my issue is, I just have no idea on how to fix it. and Ive searched for problems like mine, but I cant find one with a solid answer. if anyone can help, it would greatly be appreciated. thanks!

Creating a custom UITableViewCell

I'm trying to create a custom UITableViewCell.
From XCode 4.6 interface builder, I've set the Style property of the cell to Custom. And added controls to the cell using drag and drop. 2 UILables and a UIButton. It looks like this.
I created a separate class deriving from UITableViewCell to assign the properties of the 3 UI elements and make the changes there. I've set the cell's custom class as DashboardCell from the Identity Inspector as well.
DashboardCell.h
#import <UIKit/UIKit.h>
#interface DashboardCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *numberOfMails;
#property (weak, nonatomic) IBOutlet UILabel *mailType;
#property (weak, nonatomic) IBOutlet UIButton *numberOfOverdueMails;
#end
DashboardCell.m
#import "DashboardCell.h"
#implementation DashboardCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.numberOfOverdueMails setBackgroundColor:[UIColor colorWithRed:244/255.0f green:119/255.0f blue:125/255.0f alpha:1.0f]];
[self.numberOfOverdueMails setTitle:#"lol" forState:UIControlStateNormal];
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
In the TableViewController, I have modified the following method to return my custom cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
DashboardCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[DashboardCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
return cell;
}
My problem is even though the custom button shows up, the changes I've done (changing the background color of the button, changing the title of one UILabel) aren't showing up. What seems to be the mistake here?
The method initWithStyle:reuseIdentifier: will not be called because you're using interface builder to create a cell.
You can set the background color and title by overriding the method awakeFromNib.
You can also set these in the method tableView:cellForRowAtIndexPath:
If you get your cell from a xib or storyboard, dequeueReusableCellWithIdentifier:forIndexPath: will always return a cell -- if one exists it will reuse it, if not it will create one from the template in IB. Therefore, your if(cell ==nil) clause will never be satisfied, and in fact is no longer needed. If you want to use an init method, then use initWithCoder:

Storyboard - Multiple UITableViewControllers with the same custom cell

I occasionally find myself copy/pasting custom cells between UITableViews in my storyboard which is slowly becoming a maintenance nightmare (i.e., a simple change must now be made to each custom cell across several UITableViews).
Is it possible to create one custom cell in a storyboard or xib file and then reference it from multiple UITableViews? I'm thinking there's got to be a way to specify a NIB name for a static/prototype cell similar to how you can specify a NIB name for a UIViewController when editing a normal xib.
BTW... I know how to do this via code. What I'm looking for is a way to do this from within the storyboard editor itself.
I know of a way, but it does require a little code in a custom class. Make a subclass of UITableViewCell that loads itself from a nib. Then just set the class of your cells to this subclass. For a good method of having a view replace itself with a different version loaded from a nib see this blog post.
Actually, you don't have to create a custom class. If you're coding for version 4.0 and up, you can use a UINib to create it. You can also cache it to improve performance.
UIViewController.h
#property (nonatomic, retain) UINib *cellNib;
#property (nonatomic, retain) IBOutlet MyCustomTableViewCell *customCell;
UIViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Cache the tableviewcell nib
self.cellNib = [UINib nibWithNibName:#"MyCustomTableViewCell" bundle:nil];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCustomTableViewCell";
MyCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[self.cellNib instantiateWithOwner:self options:nil];
cell = customCell;
self.customCell = nil;
}
// Set title and such
}
Don't forget about releasing it in dealloc if not using ARC

Linking Custom NSButton to View Based Table Row and Action

I have a view based table with a custom cell view. Inside this custom cell view, I have a custom NSButton that acts like a check box (it toggles a custom image on and off). This part works well. The images toggle on and off perfectly.
What I want to do is associate the custom button in the row with the actual row in the table. When I check/click the button it will highlight the the corresponding row and then perform an action on the row in which the check box/ button is situated. For example, removing the row from the table when the NSButton is clicked.
My custom NSButton is implemented as follows:
Header file:
#import <Foundation/Foundation.h>
#interface CustomCheckButton : NSButton {
BOOL _checked;
}
#property (nonatomic, setter=setChecked:) BOOL checked;
-(void) setChecked:(BOOL) check;
#end
Implementation:
#import "CustomCheckButton.h"
#implementation CustomCheckButton
#synthesize checked = _checked;
-(id) init
{
if( self=[super init] )
{
self.checked = NO;
[self setTarget:self];
[self setAction:#selector(onCheck:)];
}
return self;
}
-(void) awakeFromNib
{
self.checked = NO;
[self setTarget:self];
[self setAction:#selector(onCheck:)];
}
-(void) setChecked:(BOOL) check
{
_checked = check;
if( _checked )
{
NSImage* img = [NSImage imageNamed:#"check_on.png"];
[self setImage:img];
[self setState:NSOnState];
}
else
{
NSImage* img = [NSImage imageNamed:#"check_off.png"];
[self setImage:img];
[self setState:NSOffState];
}
}
-(void) onCheck:(id) sender
{
self.checked = !_checked;
NSLog(#"A check box was pressed");
}
#end
The current solution does not associate the button with the row at all. When I sort the rows, for example, the selected image is not linked to the row and often stays in the same place within the table, even though a different row was selected.
Any help on this would be greatly appreciated.
How about adding a delegate field and setting it with a custom initializer? Or you could add it as a property and set it after calling alloc init. This can be done in 2 ways: via IB or programmatically.
If you want to do it programmatically, you'll need to do a couple of things:
So let's look at the class that has a UITableView element in it. Assuming this class is also the UITableViewDelegate and UITableViewDataSource, it will have to have an implementation of the data source method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
which returns a cell at a given indexPath. Here, you could instantiate your custom cell and in that, add a custom button and set it's delegate to the cell itself, by adding this to your code:
in CustomCheckButton.h:
UITableViewCell * delegate;
//...
#property (nonatomic, assign) UITableViewCell * delegate;
in CustomCheckButton.m
#synthesize delegate;
in the table view data source method:
// initialize my custom cell element, assume it has a property for a CustomCheckButton with name checkButton
// ... some code
myCell.checkButton.delegate = mycell; // link the button's delegate to the cell
// ... some other code, probably based on indexPath
return myCell;
This might seem like a big task, but you can do it in interface builder too, assuming you have a xib for your custom cell class. If you do, just open the xib. You'll probably have a button on it already; change it's class to your own CustomCheckButton and you'll be able to set its delegate property like you would normally, with ctrl-drag from the button to the cell.
Hope this helps!