I've implemented the NSComboBoxDelegate:
-(void)comboBoxSelectionDidChange:(NSNotification *)notification{
}
- (void)controlTextDidEndEditing:(NSNotification *)aNotification{
}
- (void)comboBoxWillPopUp:(NSNotification *)notification{
}
- (void)comboBoxWillDismiss:(NSNotification *)notification{
}
but I have 2 comboBoxes - with 2 different functionalities.
is there a way to know which comboBox is no on the run, and act accordingly?
or do I have to implement 2 different delegates outside? and if so - is there an easy way to transfer information back to my viewcontroller?
is there a way to get info about the sender of the notification?
For text change (controlTextDidEndEditing, controlTextDidChange...), see the following example.
- (void)controlTextDidEndEditing:(NSNotification *)obj {
if ([obj object] == combobox1) {
}
else if ([obj object] == combobox2) {
}
}
As for selection change, you need to create IBAction connections for respective objects.
The notification object ([notification object] or notification.object) will be the combo box that sent the notification.
Why don't you use tags? you can assign a tag 101 to one of them and a 102 to the other, then when they fire the delegate you just need to have an if clause to check the object's tag.
Related
I have several NSTextFields declared on my NSWindowController, all of them has as delegate the File's Owner, and respond fine to this method:
-(void)controlTextDidEndEditing:(NSNotification *)obj{
}
but I also want to know the control's value for this I used next code
-(void)controlTextDidEndEditing:(NSNotification *)obj{
if ((NSTextField *)obj == self.nombreCuentaActivoTextField) {
NSLog(#"you just edited nombreCuentaActivoTextField");
}
}
but it doesn't work, how to do that
obj is an NSNotification. You can't just cast it to an NSTextField and assume you've achieved anything useful.
The control which posted that notification and thus triggered that delegate method is the "object" of the notification. You can use [obj object] to obtain that. So, you might implement the method like so (I've renamed obj to notification for clarity):
-(void)controlTextDidEndEditing:(NSNotification *)notification{
if ([notification object] == self.nombreCuentaActivoTextField) {
NSLog(#"you just edited nombreCuentaActivoTextField");
}
}
I am trying to develop my app in Xcode 5 and debug it under iOS 7 environment.
I have a customized UICollectionViewLayoutAttributes.
I plan to do something after long pressing on UICollectionViewCell, so I override the method in UICollectionViewCell.m
- (void)applyLayoutAttributes:(MyUICollectionViewLayoutAttributes *)layoutAttributes
{
[super applyLayoutAttributes:layoutAttributes];
if ([(MyUICollectionViewLayoutAttributes *)layoutAttributes isActived])
{
[self startShaking];
}
else
{
[self stopShaking];
}
}
In iOS 6 or below, - applyLayoutAttributes: is called after I call the statements below.
UICollectionViewLayout *layout = (UICollectionViewLayout *)self.collectionView.collectionViewLayout;
[layout invalidateLayout];
However, in iOS 7, - applyLayoutAttributes: is NOT being called even if I reload the CollectionView.
Is that a bug which is gonna be fixed by Apple later on, or I have to do something?
In iOS 7, you must override isEqual: in your UICollectionViewLayoutAttributes subclass to compare any custom properties that you have.
The default implementation of isEqual: does not compare your custom properties and thus always returns YES, which means that -applyLayoutAttributes: is never called.
Try this:
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
}
if (!other || ![[other class] isEqual:[self class]]) {
return NO;
}
if ([((MyUICollectionViewLayoutAttributes *) other) isActived] != [self isActived]) {
return NO;
}
return YES;
}
Yes. As Calman said you must override isEqual: method to compare custom properties that you have. See the apple documentation here
If you subclass and implement any custom layout attributes, you must also override the inherited isEqual: method to compare the values of your properties. In iOS 7 and later, the collection view does not apply layout attributes if those attributes have not changed. It determines whether the attributes have changed by comparing the old and new attribute objects using the isEqual: method. Because the default implementation of this method checks only the existing properties of this class, you must implement your own version of the method to compare any additional properties. If your custom properties are all equal, call super and return the resulting value at the end of your implementation.
In this case, the most efficient method would be
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
}
if(![super isEqual:other]) {
return NO;
}
return ([((MyUICollectionViewLayoutAttributes *) other) isActived] == [self isActived]);
}
I have a NSTableview. I need to enable the button based on a value of a column in the tableview. For instance, In the table view i have a column, Status. I have 2 kinds of status, Withdrawn and Booked. If i click on a row which has the status as Withdrawn, i need to disable the withdraw button.
Can i be able to do it through binding? How could i do it? Pls help me out. Thanks.
Provided you create a custom NSValueTransformer, you can enable or disable the button using bindings.
You can bind the Enabled property of the button as follows:
Bind to: arrayController
Controller Key: selection
Model Key Path: status
Value Transformer: MDStatusValueTransformer
NOTE: in place of arrayController, you should select whatever the name of your array controller is in the nib file. In place of MDStatusValueTransformer, you should specify whatever class name you end up naming the class I've provided below.
As I mentioned, you'll need to create a custom NSValueTransformer. The enabled property expects a BOOL wrapped in an NSNumber, but your status property is an NSString. So, you'll create a custom NSValueTransformer that will examine the incoming status NSString, and return NO if status is equal to #"Withdrawn".
The custom NSValueTransformer should look something like this:
MDStatusValueTransformer.h:
#interface MDStatusValueTransformer : NSValueTransformer
#end
MDStatusValueTransformer.m:
#implementation MDStatusValueTransformer
+ (Class)transformedValueClass {
return [NSNumber class];
}
+ (BOOL)allowsReverseTransformation {
return NO;
}
- (id)transformedValue:(id)value {
if (value == nil) return nil;
if (![value isKindOfClass:[NSString class]]) return nil;
if ([value isEqualToString:#"Withdrawn"]) {
return [NSNumber numberWithBool:NO];
}
return [NSNumber numberWithBool:YES];
}
#end
How can I change the functionality of a button that I used previously? For example, If I had a button that did "Proceed/Cancel" and let's say you "Proceed" the button would change to something such as "View/Go Back"? Basically I want to re-use the same button for something else, but since I don't know how maybe someone can help me understand it better. Thank you.
- (IBAction)someButton:(NSButton *)sender {
if ([someString isEqualToString:someThing]) {
isAllowed = YES;
[oneButton setTitle:#"Proceed"];
[self continue];
}
else {
[oneButton setTitle:#"Cancel"];
return;
}
}
- (void)continue {
// I would like to make someButton (above) take on different functionality
// here if that's even possible. such as:
[oneButton setTitle:#"View"];
[self whatNow];
At some point in your program lifecycle you could replace the previous target and/or action of a NSButton by the desired one.
[oneButton setAction:#selector(continue)];
This will cause your continue selector to be called instead of the someButton: for the oneButton instance.
OBS: just pay attention at your selectors as the one from the NIB file has a parameter #selector(someButton:) and the one you are creating does not have any, so it stays as #selector(continue)
as seen here: Cocoa forControlEvents:WHATGOESHERE
I have the following, seemingly simple piece of code handling button taps in an iOS application:
- (IBAction)tapKeypadButton:(UIButton *)sender {
NSString *buttonLabel = sender.titleLabel.text;
if ([buttonLabel isEqualToString:#"<"]) {
[self _tapBackButton];
} else {
[self _tapDigitButton:buttonLabel];
}
}
To completely follow the Clean Code principles by Robert C. Martin, would I need a ButtonTapFactory or something in the same line?
You have two types of buttons, with different behaviors (back button and digit button). To make this code clean, you should have two actions for each type. The type should not be determined by the contents of the text inside the button, but through a semantically meaningful way. (i.e. subclass).
Further, an action method should only contain a call to another method that does the actual logic. Everything else is not testable. In code:
- (IBAction) tapBackButton:(id) sender
{
[self _tapBackButton:sender];
}
- (IBAction) tapDigitButton:(id) sender
{
[self _tapDigitButton:sender];
}
This way you can have unit tests calling your methods without your UI code interfering. Please also note that I removed the label from the call to _tapDigitButton. The digit should not be parsed from the label, but be passed in a more semantically stable way, for example using the tag property.