Accessing NSStrings from other classes - objective-c

i hope you can help me solving my actual problem:
I´ve set up a new project with a navigation controller. For the table view of the project I´ve added a new class for it, called "TableViewController.h" and "TableViewController.m".
In this class I´ve declared in .h a property for a NSString to access it from other classes, like this:
#property (strong, nonatomic) NSString *testString;
In .m I´ve synthesized it as followed:
#synthesize testString;
Now I set in - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath-Method of the table view controller the following:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
testString = #"Hello, World!";
}
Now created a new UIViewController class for the next view which should appear when I´m tapping on a cell (all that works so far). In this UIViewController, called "SecondView" I imported the .h-File of TableViewController.
Further I have this code in SecondView.m:
-(void) viewDidLoad
{
[super viewDidLoad];
TableViewController *demoObject = [TableViewController alloc] init]
NSLog (#"Teststring is: %#" [demoObject.testString]);
}
Now when I start the Simulator I get this Output:
Teststring is: (null)
When I NSLog the testString in TableViewController I get "Hello, World", but why isn´t it "transferred" to the SecondView class and generates the needed output?

You are logging the string in viewDidLoad, which gets called long before it is set in the table views's didSelectRow method. You should also use self.testString = ...

how do you expect the data to 'transfer'? you have to pass it .. in tableView:didSelectCellAt:row (where you push the 2nd view) you have to say:
2ndView.testString = self.testString;

Related

Populate NSTableView with a new object by clicking a button

Im trying to populate an NSTableView with a custom object by clicking a button. My custom class has just NSString properties: title and volume. I customized the init method to create an object and add it to my array that is hooked up to my table view. Then on the method for my button I had it create another object and add it to the array. When I run the program the object from the init method does display correctly. However, when I click my button I get nothing.
Here is the code for my header file:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDataSource>{
NSMutableArray *_myArray;}
#property (weak) IBOutlet NSTableView *tableView;
- (IBAction)button:(id)sender;
#end
and here is my implementation:
#import "AppDelegate.h"
#import "trade.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
-(id)init{
self = [super init];
if (self){
_myArray = [[NSMutableArray alloc]init];
trade *firstTrade = [[trade alloc]init];
[firstTrade setTitle:#"Trade One"];
[firstTrade setVolume:#"Volume 01"];
[_myArray addObject:firstTrade];}
return self;}
- (IBAction)button:(id)sender {
trade *secondTrade = [[trade alloc]init];
[secondTrade setTitle:#"Trade two"];
[secondTrade setVolume:#"Volume 02"];
[_myArray addObject:secondTrade];
[_tableView reloadData];}
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return _myArray.count;}
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
if ([tableColumn.identifier isEqualToString:#"Title"]){
trade *item = [_myArray objectAtIndex:row];
return item.title;
}else{
trade *item = [_myArray objectAtIndex:row];
return item.volume;}}
#end
Not sure what I'm doing wrong here as what I did in the init method is pretty much the same thing I did in button method. Any help is greatly appreciated. Here is a picture of the program after I run it:
tableView program
As you can see my first object appears in the table view, but not the second.
While looking at this project I duplicated the [_tableView reloadData]; line and placed a breakpoint on the second one so I could see what was going on right after the first one is called. One thing I noticed is that _myArray does now contain 2 objects after the button click.
However, when I look into _tableView it shows that _myArray only contains 1 object. How is it that the object is actually getting added but the table view is only getting 1?
Here is a picture for reference:Debug

How to Share Methods Between Classes

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 ?

Can't pass data with prepareForSegue:

I am trying to pass data from a UITextView in one view controller to UITextView in another view controller. My application is using Storyboards.
in the first view controller I say:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
LyricKaraokeViewController *karaokeController = segue.destinationViewController;
karaokeController.hidesBottomBarWhenPushed = YES;
SongDoc *song = [[SongDoc alloc] initWithTitle:#"Title" lyrics:#"Test" thumbImage:nil];
karaokeController.detailItem = song;
NSLog(#"%#", karaokeController.detailItem.data.lyrics);
}
The NSLog outputs the appropriate text
In my second view controller I declare this interface:
#class SongDoc;
#interface LyricKaraokeViewController : UIViewController
#property (nonatomic, retain) SongDoc * detailItem;
#end
and this implementation ( just showing viewDidLoad for simplicity ):
- (void)viewDidLoad
{
NSLog(#"%#", self.detailItem.data.lyrics);
[super viewDidLoad];
}
and I confirm that there is the properties data.lyrics in the detailItem because we are passing in a SongDoc object and I output the SongDocs contents in prepareForSegue just prior....
My problem is in the second view controller I am receiving an error saying the detail item doesn't declare the property lyrics
But I know this is untrue so why is this happening?
any help would be great thanks :)
#class SongDoc;
only tells the compiler that SongDoc is a class, but does not read the implementation file. You have to
#import "SongDoc.h"
instead, so that the compiler knows which properties are declared by the class.

UITableView delegates are not called

I have a tableview with external delegate controller. Despite content table view array is well populated, and numberOfSectionsInTableView: and
-tableView: numberOfRowsInSection: are called, but-tableView: cellForRowAtIndexPath: is not called.
Issued table view is set in that ways:
CompeticionViewController.h
....
#property (retain, nonatomic) IBOutlet UITableView *calendarioTable;
#property (strong, nonatomic) calendarioViewController *calendarioController;
....
calendarioTable = [[UITableView alloc] init];
calendarioController = [[calendarioViewController alloc] init];
[calendarioTable setDelegate:calendarioController];
[calendarioTable setDataSource:calendarioController];
calendarioController.calendarioArray = [[NSMutableArray alloc] init];
[calendarioController.calendarioArray addObjectsFromArray: self.calendarioarray];
[calendarioTable reloadData];
EDITED:
calendarioViewController.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [calendarioArray count];
}
Many thanks
In .xib file link delegate and datasource with File's owner or write
tableview.delegate=self
tableview.datasource=self;
You have used IBOulet for tableview then why are u allocating it as its not need memory already allocated.
Now check in xib of your view controller that tableview is binded and its delegate and datasource provided to file owner.
-----------------------------------------OR------------------------------------------------
add this line in viewDidLoad method
yourtableview.delegate=self
yourtableview.datasource=self;
Now After using IBOulet for tableview you will have bind it with file owner and ViewController interface implements both the <UITableViewDelegate> and <UITableViewDataSource> protocols
Now check array you are providing to tableview has content in it
Edit : Add OR code and done formatting
Be sure that your CompeticionViewController interface implements both the <UITableViewDelegate> and <UITableViewDataSource> protocols.

How to push a view from a UITableViewCell

I have a UITableViewController that has custom cells that I have customized with my own subclass.
In this subclass, I've added a button and I want to push a view into the stack of the navigation controller. I have no idea on how to do that since I don't know how I can access to the navigation controller from my custom cell.
Any idea?
Need more infos here. What class holds the table, what class is the tableview delegate?
In the most simple case you're working in one single class. Than it would be [self.navigationController pushViewController: xyz].
But if you have your own subclassed UITableViewCells, than you need to communicate between the cell class and the viewcontroller. You could do this via setting a property in the cell class or your own customCell delegate.
You could also just send a Notification ([[NSNotificationCenter defaultCenter] postNotification: #"cellButtonTouchedNotification"]) on which your viewController is listening ([[NSNotificationCenter defaultCenter] addListener: self target: #selector(...) name: #"cellButtonTouchedNotification"]). In this case you could use the userInfo property to remember which cell was touched.
Anotherway is to make the button accessible from outside (a property eg). Then you could add the target in your tableViewDelegate's method cellForRowAtIndexPath:. Smth. like [myCustomCell.button addTarget: self selector: #selector(...)]; You could use tags to identify the row myCustomCell.button.tag = indexPath.row.
Use delegation. Here a simple example.
//.h
#protocol MyTableViewCellDelegate;
#interface MyTableViewCell : UITableViewCell
#property (assign, nonatomic) id <MyTableViewCellDelegate> delegate;
//your code here
#end
#protocol MyTableViewCellDelegate <NSObject>
#optional
- (void)delegateForCell:(MyTableViewCell *)cell;
#end
//.m
#implementation MyTableViewCell
#synthesize delegate = _delegate;
- (void)prepareForReuse {
[super prepareForReuse];
self.delegate = nil;
}
- (void)buttonAction {
if ([self.delegate respondsToSelector:#selector(delegateForCell:)])
[self.delegate delegateForCell:self];
}
#end
When you click the button you send a message to the delegate for your cell (e.g. the table view controller that is inserted into the navigation controller).
Here the controller
#implementation YourController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *reuseIdentifier = #"MyCustomCell";
MyTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (cell == nil)
cell = [[[MyTableViewCell alloc] initWithMyArgument:someArgument reuseIdentifier:reuseIdentifier] autorelease];
[cell setDelegate:self];
// update your cell
return cell;
}
- (void)delegateForCell:(MyTableViewCell *)cell {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// do your stuff
[self.navigationController pushViewController:...];
}
#end
Hold a pointer to your UITableViewController in the cell. You can pass it in the cell's constructor or set it later. Then you can call the pushViewController on the table view controller.
Even more beautiful solution would be to define a delegate for your cell, say ButtonCellDelegate that has a buttonClicked callback. You implement the delegate in your UITableViewController (or any other place where you have access to the view controller). Then you pass the delegate to the cell as described above and call the callback function from the cell when the button is clicked.