Working backwards from null - objective-c

I know that once you get better at coding you know what variables are and null popping out here and there may not occur. On the way to that state of mind are there any methods to corner your variable that's claiming to be null and verify that it is indeed null, or you just using the wrong code?
Example:
-(IBAction) startMotion: (id)sender {
NSLog(#"Forward or back button is being pressed.");
UIButton * buttonName = (UIButton *) sender;
NSLog(#"Button Name: %#", buttonName.currentTitle);
}
Button Name: (null) is what shows up in the console
Thanks

According to Apple's docs, the value for currentTitle may be nil. It may just not be set.
You can always do if (myObject == nil) to check, or in this case:
-(IBAction) startMotion: (id)sender {
NSLog(#"Forward or back button is being pressed.");
UIButton * buttonName = (UIButton *) sender;
if (buttonName != nil) {
NSString *title = buttonName.currentTitle;
NSLog(#"Button Name: %#", title);
}
}
Another way to check if the back or forward button is pressed, is check the id itself.
//in the interface, and connect it up in IB
//IBOutlet UIButton *fwdButton;
//IBOutlet UIButton *bckButton;
-(IBAction) startMotion: (id)sender {
NSLog(#"Forward or back button is being pressed.");
UIButton * buttonName = (UIButton *) sender;
if (buttonName == fwdButton) {
NSLog(#"FWD Button");
}
if (buttonName == bckButton) {
NSLog(#"BCK Button");
}
}
also, make sure your outlets and actions are all connected in IB, and that you save and re-build the project. I've gone where I changed somehting in IB, saved the .m file (not the nib) and was like "why isn't this working???"

I was using the wrong field in Interface Builder I was using Name from the Interface Builder Identity instead of Title from the button settings.

buttonName cannot be null, otherwise buttonName.currentTitle would produce an error.
Therefore the currentTitle attribute itself must be null.
Or, maybe currentTitle is a string with the value (null).
In general, in Objective-C, if you have [[[myObject aMethod] anotherMethod] xyz] and the result is null it's difficult to know which method returned null. But with the dot syntax . that's not the case.

Related

Issue with a checkBox in a viewbased NSTableView

I have an NSDictionary that holds all the data:
One title (not important for this question)
One link (not important for this question)
One array of NSDictionary containing again 1 title and 1 link
I'm displaying this data in a view based table view like this:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tv
{
if (tv == _downloadTable)
//I use this "if" because I have another tableView that has nothing to do
//with this one
{
return [[myDictionary objectForKey:#"myArray"] count];
}
}
I want 2 columns in this tableView, one to display the title and one with a checkbox, that would do something letting me know which row is checked.
- (NSView *)tableView:(NSTableView *)tv viewForTableColumn :(NSTableColumn *)tableColumn row :(NSInteger)row
{
if (tv == _downloadTable)
{
if (tableColumn == _downloadTableTitleColumn)
{
if ([[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"])
{
NSString *title = [[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"];
NSTableCellView *result = [tv makeViewWithIdentifier:tableColumn.identifier owner:self];
result.textField.stringValue = title;
return result;
}
}
if (tableColumn == _downloadTableCheckColumn)
{
NSLog(#"CheckBox"); //I wanted to see exactly when that was called
//But it didn't help me :(
NSButton *button = [[NSButton alloc]init];
[button setButtonType:NSSwitchButton];
[button setTitle:#""];
return button;
}
}
}
Right now when I run it and click on the checkbox it does nothing
(of course because I don't know how to make it do something.
Where should I put the code that should do something?
The main goal is an editable list of downloads, right now the list is displayed, with the checkbox right next to the title at each lines.
I would like to know which checkBox are checked and which are not.
I tried this:
[button setAction:#selector(checkBoxAction:)];
- (void)checkBoxAction: (id)sender
{
NSLog(#"I am button : %# and my state is %ld", sender, (long)[sender state]);
}
But I can't figure out how to get the row of that button, to know which title is associated with this checkBox.
I also tried the setObjectValue method of the tableView without success.
The way I would like it to work is:
I have a "start downloading" button that check if each checkbox is checked or not and launch the next action (downloading) only with the checked row.
I would like to avoid bindings because I plan to make it work on iOS too and I don't want to have different code for iOS.
You can use the NSTableView method -rowForView: to get the row a particular view is in.
In your case you'd have something like this:
- (void)checkBoxAction:(id)sender
{
NSInteger row = [_downloadTable rowForView:sender];
NSLog(#"The button at row %ld was clicked.", row);
}
Here are the docs for NSTableView: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSTableView_Class/Reference/Reference.html
You could try using the button' tag property setting it for each button you place as the number (location) in the tableview. Look here!!!
Detecting which UIButton was pressed in a UITableView
[EDIT1]
If people actually decided to read the linked post you would realize that the answer is actually there.
Try adding:
[button setTag:row];
[button addTarget:self action:#selector(checkBoxAction:) forControlEvents:UIControlEventTouchUpInside];
inside the else of your viewForTableColumn routine:
In your checkBoxAction routine:
- (void)checkBoxAction: (id)sender{
NSLog(#"I am button : %# and my state is %#", sender.tag, [sender state]);
}
I also think that once you begin digging further into your code, you are going to want to start using the auto-dequeuing capability of the TableViewCell objects. I believe that you are going to find yourself in a memory alloc/dealloc problem.

Simple bool switching not working?

I am flipping the value of a simple BOOL like this:
active = !active;
NSLog(#"%#", active? #"active" : #"not active");
I've done this numerous times but right now, for some reason it's not working and it's really pissing me off. When ever the flow hits here, it always prints "active". It's not switching!!
Here's my interface:
#interface HeaderView : UIView {
UILabel *label;
UIButton *button;
UIImageView *background;
BOOL active;
int section;
__weak id<HeaderViewDelegate> delegate;
}
and function where the action is performed:
- (void)actionTUI:(id)sender {
active = !active;
NSLog(#"%#", active? #"active" : #"not active");
UIImage *image = nil;
if (active) {
image = [UIImage imageNamed:#"active.png"];
} else {
image = [UIImage imageNamed:#"unactive.png"];
}
[button setBackgroundImage:image forState:UIControlStateNormal];
[delegate headerView:self toggled:active];
}
Thanks
BOOLean values, as with all other types, are initialized to NULL (0, FALSE, NO) at runtime unless assigned a different value. You are assigning a not(NO) to your BOOL, which prints YES at every run.
Also, your NSLog() is weird, it's probably evaluating itself the wrong way, and most likely contributing to the problem. It should not include the literal:
NSLog(active? #"active" : #"not active");
Ok, the problem was that after toggling, I was reloading the tableview which apparently recalls:
- (UIView *)tableView:(UITableView *)_tableView viewForHeaderInSection:(NSInteger)section {
which caused a new header view to be allocated/initialized with active set to NO and right after toggling, set to YES. That's why every time, even after flipping the values it was set to active (because right after, it would get discarded and a new header view would come to it's place).

IBAction connected with button but need a void

I have i IBAction and it's connected with a button in .xib. But for a action o needed this code;
- (void) reportScore: (int64_t) score forCategory: (NSString*) category
{
GKScore *scoreReporter = [[GKScore alloc] initWithCategory:category];
scoreReporter.value = counter;
[scoreReporter reportScoreWithCompletionHandler: ^(NSError *error)
{
[self callDelegateOnMainThread: #selector(scoreReported:) withArg: NULL error: error];
NSLog(#"Nice: %d", counter);
}];
}
Is there a way to connect my button with the void? Or something like that?
- (IBAction) subScore {
//data
}
IBAction(and IBOutlet) is just used to let XCode's Interface Builder(IB) know that there's a function exist. If you want use void, okay, but you'll not get the function shown in Interface Builder.
IBAction is a special keyword that is used only to tell Xcode(Interface Builder) to treat a method as an action for target-action connections. IBAction is defined to void.
IBOutlet is a special keyword that is used only to tell Xcode(Interface Builder) to treat the object as an outlet. It’s actually defined as nothing so it has no effect at compile time.
You can set the function(which is defined with void, and note IBAction is okay either, but needless here) to your button target like this:
[yourButton addTarget:self action:#selector(yourButtonFunction:) forControlEvents:UIControlEventTouchUpInside];
Generally, if you create your code programmatically(without using XCode's Interface Builder), you do not need IBOutlet or IBAction anymore. ;)

UITextField editingChange Control Event not works

I have some textfields and I want to do when I change textfield1 text set text to other textfields. My code below. But it not works. How can I solve this?
- (IBAction)TCKimlikTextChange:(id)sender {
[TCKimlikText addTarget:self action:#selector(yourMethod: ) forControlEvents:UIControlEventEditingChanged];
}
-(void)yourMethod: (UITextField*)tf_{
if (tf_) {
if (TCKimlikText.text == #"1") {
AdinizText.text = #"Hacer";
}
}
}
Your code is very abstract. yourMethod, tf_ TCKimlikTextChange are all expressions that are not very human readable. You should work on your variable names.
I suppose your first method is a button handler. It just assigned a target and action to the text field, but does not call any method. You do not need that action if you use the delegate protocol.
To solve your problem: implement the UITextField delegate methods. Make sure you set the delegate (probably self) for your text fields. Your view controller must mention the <UITextFieldDelegate> protocol in its .h file. Thus, in textField:shouldChangeCharactersInRange:replacementString::
if ([textField.text isEqualToString:#"1"]) {
displayLabel.text = #"Hacer";
}
Notice that you need isEqualToString: to compare strings, a simple == won't do.
If u are want to change on the click of the return button use the delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if(textField == field1)
[field2 setText:field1.text];
[field1 resignFirstResponder];
return YES;
}
or u can use other delegates too like:
– textFieldShouldBeginEditing:
– textFieldDidBeginEditing:

disable button when textfields are empty

hi im a beginner to programming and have been stuck on this task for ages and seem to be getting nowhere.
basically i have several textfields that generates the input information on a different page when the user presses a button. i would like the button to be disabled until all text fields are filled with information.
so far i have this:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// make sure all fields are have something in them
if ((textfbookauthor.text.length > 0)&& (textfbookedition.text.length > 0)&& (textfbookplace.text.length > 0)&& (textfbookpublisher.text.length > 0) && (textfbookpublisher.text.length > 0) && (textfbooktitle.text.length > 0) && (textfbookyear.text.length > 0)) {
self.submitButton.enabled = YES;
}
else {
self.submitButton.enabled = NO;
}
}
the problem is the 'submitButton' is coming up with an error, what needs to go in its place?
i tried to put my button 'bookbutton'in it instead but its not working.
this is my function for the 'generate' button
-(IBAction)bookbutton:(id)sender;
{
NSString* combinedString = [NSString stringWithFormat:
#"%# %# %#.%#.%#:%#.",
textfbookauthor.text,
textfbookyear.text,
textfbooktitle.text,
textfbookedition.text,
textfbookplace.text,
textfbookpublisher.text];
BookGenerate*bookg = [[BookGenerate alloc] init];
bookg.message = combinedString;
bookg.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:bookg animated:YES];
[BookGenerate release];
}
if anybody knows how i can make it work or what i need to add please help.
thanks in advance
Make an Outlet for every UITextField and create an IBAction in your .h:
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
IBOutlet UITextField *textField3;
IBOutlet UIButton *button
- (IBAction)editingChanged;
Connect all the outlets and connect the IBAction to every textfield with editingChanged:
- (IBAction)editingChanged {
if ([textfield1.text length] != 0 && [textfield2.text length] != 0 && [textfield3.text length] != 0) {
[button setEnabled:YES];
}
else {
[button setEnabled:NO];
}
}
Note that you can also use [textfield.text isEqualToString:#""] and put a ! in front of it (!means 'not') to recognize the empty textField, and say 'if the textField is empty do...'
And:
- (void)viewDidLoad {
[super viewDidLoad];
[button setEnabled:NO];
}
If you have a button and you want to enable it only if there is a text in a textfield or textview, implement the follow method
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (textView.text.length > 1 || (text.length > 0 && ![text isEqualToString:#""]))
{
self.button.enabled = YES;
}
else
{
self.button.enabled = NO;
}
return YES;
}
Few solutions are available on these posts as well
Very Similar Query
A different version of it
Key here is using (extending) UITextFieldDelegate class and it's associated function
//Need to have the ViewController extend UITextFieldDelegate for using this feature
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if !text.isEmpty{//Checking if the input field is not empty
button.userInteractionEnabled = true //Enabling the button
} else {
button.userInteractionEnabled = false //Disabling the button
}
// Return true so the text field will be changed
return true
}
You should use" textfield should change chracters in range" (see apple docs for uitextviewdelegate). because it updates as users type information." Textfield did end editing" only fires when the users finishes editing a textfield or hits enter. In most cases, someone will fill in the last field and leave the cursor sitting there and expect the button to become enabled...but that wont happen using "textfield did end editing" just because they entered input.
You can also do this to check the length
if([self.textfiele.text isEqualToString:#""])
In addition to having IBOutlets for each UITextField, it might be helpful to have an IBOutletCollection declared that contains all 3 text fields in an array.
#property (nonatomic, retain) IBOutletCollection(UITextField) NSArray *textFields;
Then in your implementation just #synthesize textFields and you can quickly loop the text fields it contains, checking for text.
- (IBAction)editingChanged
{
BOOL buttonShouldBeEnabled = YES;
for (UITextField *field in self.textFields)
if (!field.text.length)
buttonShouldBeEnabled = NO;
button.enabled = buttonShouldBeEnabled;
}