Get current object in function? - objective-c

I'm trying to code a simple UITextField and I have a simple question:
Im using this to 'empty' the UITextField:
-(IBAction)editbegin{
campo1.text="";
}
The problem is: want to use this function in more than one TextField. So, how can I 'grab' the object, so I can get the 'text'? Already tried 'self.text', but it returns the view.
Thanks.

Check out the UITextField documentation. It looks like you are trying to "reinvent" the wheel.
If all you want to do is clear the textfield once a user begins editing, there is a function for that.
When creating your text field, just set:
textField.clearsOnBeginEditing = YES;
The same option is also available on Interface Builder if that's what you are using.
Specific documentation link here http://developer.apple.com/library/ios/DOCUMENTATION/UIKit/Reference/UITextField_Class/Reference/UITextField.html#//apple_ref/occ/instp/UITextField/clearsOnBeginEditing

Include the "sender" property.
-(IBAction)editbegin:(id)sender{
sender.text=#"";
}
Edit: Apparently you need to cast it? I thought you could send any message to id. I guess this is better code, anyway.
-(IBAction)editbegin:(id)sender{
UITextField *field = (UITextField *)sender;
field.text=#"";
}

Related

Override a property to make it read-only from the subclass

I would like to subclass UILabel in such a way that the user of the class cannot set the text directly through label.text = #"foo". Instead I'd like to set the text from inside the subclass depending on some values.
What I tried:
BalanceLabel.h:
#interface BalanceLabel : UILabel
#property(nonatomic,copy, readonly) NSString *text;
#end
However, I get a warning telling me I'm restricting text access (like I wanted to) but I don't get any compile time errors if I try to set the text directly using an object of my subclass.
You can't do this. As a trivial example as to why not, just think of how the following code should behave:
UILabel *label = [[BalanceLabel alloc] init];
label.text = #"string";
That code creates a BalanceLabel, but stores it in a variable of type UILabel, which means that the subsequent setting of the .text property can't know that you tried to make the property readonly in BalanceLabel.
Unfortunately there's not much you can do about this. You could override the setter to throw an exception, which will let users know what they did wrong, but of course will also crash the app.
You should be putting the logic into controller that managed the view instead of view directly.
I assume you have some view that gets updated with new values and you want to update the BalanceLabel based on these new values.
Your controller is a delegate for your view so it receives new values, from either user or other modules of your app that populated new values (like loaded from file, downloaded from network and so on).
Your controller then figures out which bits of view needs update and sets new values - in your case calculate balance, I assume

How to bind a buttons title to a particular value in an array IOS?

I have six on-screen buttons whose titles need to correspond to six elements in an NSMutableArray, when the value in the array changes, I also need the title to change with it. I am having trouble figuring out how to create that constantly updating line to the button, I'm still quiet new to objective-c development as well as Xcode.
I also need to make sure that when there is no value at that particular index of the array, the button cannot be clicked on
here is an example of one of the buttons
- (IBAction)card1Pressed:(id)sender {
if (self.userHasEnteredFirstNumber) {
if (!self.userHasEnteredSecondNumber) {
self.secondNumber = [sender currentTitle];
}
}
else{
self.firstNumber = [sender currentTitle];
}
}
The end goal is to have the user press two buttons, then chose weather to add, subtract, multiply, or divide them. After they pick one of those four operations, the values that the buttons were assigned to in the array will be removed and replaced with whatever the new number is. So after they do this once there will only be 5 numbers left in the array, then 4, then 3..... and so on.
The numbers will be drawn and added to an NSMutable array titled currentHand
UPDATE: Using UIOutletCollection I linked the buttons to the method like this
the link to the picture is here "sorry about not being able to directly post it but new users must have a reputation of 10 before they can"
link to photo of declaration and implementation with interface-builder of IBOutletCollection
was this correct?
the code for the header file regarding the IBOutletCollection is as follows "please note that this has been connected to the six buttons I want to use it with in interface builder, a picture of it is shown above"
#property (nonatomic,retain) IBOutletCollection (UIButton)NSArray *buttonArray;
the code in the implementation file regarding the IBOutletController is as follows
# synthesize buttonArray = _buttonArray;
You want to use Key-Value observing, check out this from the Apple documentation:
https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i
Okay okay, so essentially you have a 'Button'-Array, whose 'Caption' is served by a NSMutableArray, which can easily be changed around, correct?
Now, this is only how I'd do it, there may be better solutions out there, but here goes:
You need a 'change' interface, which is called EACH time, something happens to your NSMutableArray. For example (since I don't know WHAT exactly is in that array of yours):
- (void) ChangeArray:(int)IDofElement (NSString *)newValue {
[arr replaceObjectAtIndex:IDofElement withObject:newValue]; //Updates/Empties the indexed Element.
if(newValue != nil) {
[buttons[IDOfElement] setText:newValue];
}
buttons[IDOfElement].enabled = (newValue != nil); //Makes Button 'clickable'
}
Like this, each time the value inside that array of yours gets changed, the corresponding caption also gets updated. Of course you would need an array of the buttons for this to work, but I don't think that's the big problem.
Another possible solution: Save a reference to the button inside of the object that's stored in the array and whenever the value is changed, change the button's caption too.
Does this help? Mind you, this is not the 'perfect solution', but something I'd come up with.
Please also note, that this is just from the top of my head and probably faulty at some points. But it should be able to point you in the general direction.

Resizing NSTokenField after populating with tokens

I am using an NSTokenField as a way for users to enter tags. Everything works fine and it hooks up with CoreData managing the tags both when the user adds or deletes a tag.
I recently added logic so that the NSTokenField would resize vertically as the user adds tags and they break to the next line using Andrew Bowman's IFVerticallyExpandingTextField. Again this all works fine.
The issue is that when I have to initially populate the NSTokenField with tags, I need it to resize. I populate the field by calling:
[tagField setObjectValue: anArray];
Where anArray is a series of objects that represent a tag or a Token. This in turn calls the NSTokenField delegate method
tokenField:displayStringForRepresentedObject:
Which returns the string representation for the object passed in the previous array.
I need to resize the NSTokenField after all of the calls to displayStringForRepresentedObject. Does anyone have any ideas of a notification or a way of finding out that it's all done? Even a way of calling the resize in between each call to displayStringForRepresentedObject would probably work.
Thanks in advance.
You might try something similar to -setNeedsDisplay: and -displayIfNeeded ... i.e., -setNeedsSizeToFit: and -sizeToFitIfNeeded.
You'll just need a "needsSizeToFit" BOOL flag and the -setNeedsSizeToFit: and -sizeToFitIfNeeded methods.
After you set your tokens, call -setNeedsSizeToFit:YES. It in turn will set the instance's needsSizeToFit flag, then if the flag is YES, it will call [self performSelector:#selector(sizeToFitIfNeeded) withObject:nil afterDelay:0]. Your -sizeToFitIfNeeded method will check if your needsSizeToFit flag is YES, call [self sizeToFit], then set the needsSizeToFit flag to NO.
Update
Here's a complete class (JLNAutoSizingTokenField) that does basic autosizing as described above. The only augmentation was to call this in the afore-mentioned delegate method:
- (NSString *)tokenField:(NSTokenField *)aTokenField
displayStringForRepresentedObject:(id)representedObject
{
[(JLNAutoSizingTokenField *)aTokenField setNeedsSizeToFit:YES];
return representedObject;
}

How do I set Cocoa NSLevelIndicatorCell values?

I have a tableview. One of the columns in the tableview uses an NSLevelIndicatorCell.
I want to be able to allow the user to edit the warn and critical values for the level indicator such that when they enter a value into a a "warning level" textbox, it changes the warn value of the level indicators being displayed in ALL of the tableview's rows.
I am very much a newbie with Objective-C so all I can figure out so far is that I must need a delegate method to watch the textbox BUT if I succeed in doing that, how on earth do I send the new value to the particular tableview column so that the update happens to ALL of the rows (i.e. how do I send what message to the tableview and target a cell within a column within a tableview)?
Here is the code to the solution I came up with should anyone need it.
- (IBAction)setWarningLevel:(id)sender {
double v;
NSScanner *ns = [NSScanner scannerWithString:[warnLevel stringValue]];
[ns scanDouble:&v];
[levelIndicator setWarningValue:v];
}
This is a textbook case for using Cocoa bindings. Just bind the value of the text field to the NSLevelIndicatorCell in your table view (do that in Interface Builder). The updates should happen automagically.
I think it should apply for all the cells in the table view if you apply the binding to the cell in IB. However if it doesn't, you will need to write a couple lines of code that set up the binding every time a new row in the table is created. That link above will explain everything in detail, but basically you will be setting up a Key-Value Observer relationship in code between the text field and the instance of the level indicator in the row being created.
I think you may have overdone it.
NSTextField subclasses NSControl, so you need to look in the docs for NSControl for a useful function.
Try re-writing it like this; assuming you're taking the value from a warnLevel textfield.
- (IBAction)setWarningLevel:(id)sender {
double v = [warnLevel doubleValue];
[levelIndicator setWarningValue:v];
}
Although this is usually shortened to this;
- (IBAction)setWarningLevel:(id)sender {
[levelIndicator setWarningValue:[warnLevel doubleValue]];
}
You should probably have some validation that the textfield has a valid number. If you're only choosing a couple of numbers have a look at using a stepper control.
Usually, with Cocoa, if you feel like you're jumping through too many hoops, there is sometimes an easier way.
Usually ;-)

How do I keep an NSPathControl updated with the path of the selected cell in an NSBrowser

I need to keep an NSPathControl updated with the currently selected path in an NSBrowser, but I'm having trouble figuring out a way of getting notifications when the path has changed from the NSBrowser. The ideal way to do this would just to be to observe the path key path in the NSBrowser, but that gives a KVO can only observe set<key> methods which return void message and no updates (setPath returns a bool success value).
I also tried observing the selectedCell key path, but I'm not getting notifications when the selection there is changed.
Is there some other really obvious way to do this that I'm missing?
Courtesy of Rob Keniger over at Cocoa Dev:
Have you looked at the SimpleBrowser
example in /Developer/Examples? It
shows how to get the current selection
when it is changed by the user,
basically by just setting up the
action of the NSBrowser.
That is indeed the way to do it. Just implement a method like - (void)browserClicked: in your controller and map it to the NSBrowser's action in interface builder with whatever you want to happen each time the selection changes inside that method, e.g.
- (void)browserClicked:(id)browser {
self.pathToSelectedCell = [browser path]; // NSPathControl is bound to pathToSelectedCell
}
I just checked in IB, and it looks like NSBrowser has a selection index paths binding (an array of NSIndexPath objects) that you could possibly monitor with KVO. It's strange but I don't see any mention of it in the docs, so you might need to do a little research to see if that's something you should or shouldn't use, even if it seems to work. If it does, in your KVO observation method you would find the browser's current path, and convert that to an NSURL the path control can use.
If that doesn't work there's also the delegate methods - (BOOL)browser:(NSBrowser *)sender selectRow:(NSInteger)row inColumn:(NSInteger)column and - (BOOL)browser:(NSBrowser *)sender selectCellWithString:(NSString *)title inColumn:(NSInteger)column.
As of 10.6, one can find out which items are selected, by using the delegate callback as follows:
- (NSIndexSet *)browser:(NSBrowser *)browser selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes inColumn:(NSInteger)column
{
NSLog(#"New first item of the new selection is at index %#", [proposedSelectionIndexes firstIndex]);
// Do something with the selected index or indicies
return proposedSelectionIndexes; // Allow the selection to occur by not changing this
}