using int selector for ccmenuitem - objective-c

My CCMenuItem has two methods in selector
menuItem = [[CCMenuItemSprite
itemFromNormalSprite:[CCSprite spriteWithSpriteFrameName:#"menuItem.png"]
selectedSprite:[CCSprite spriteWithSpriteFrameName:#"menuItem.png"]
target:self
selector:#selector(methodName:anotherParam:)] retain];
I'd like to send the an int from CCMenuItem so that I'd could switch the cases based on the int of the CCMenuItem
something like this:
- (void)methodName:(id *)sender anotherParam:(int *)intNumber {
CCMenuItemSprite *menuItem = (CCMenuItemSprite *)sender;
switch (anotherParam) {
case 1:
//My case
break;
}
How can I send an int from CCMenuItem in order to switch my cases?

You can use the userData property of a CCNode for this, or you could set an associated object.
Eample:
CCNode *myNode = [CCNode node];
myNode.userData = (void *) intVal;
// in callback
CCNode *myNode = (CCNode *) sender;
int anotherParam = (int) myNode.userData;
To set an associated object, you would do something like this:
objc_setAssociatedObject(myObject, "anotherParam", (id) myInt, OBJC_ASSOCIATION_ASSIGN);
// in callback
int anotherParam = (int) objc_getAssociatedObject(myObject, "anotherParam");
Note that key is of type void * so you could put any value there (NSObject, NSString, C-string, int value, etc.)

Just tag the CCMenuItem:
menuItem.tag = 1;
Then get it from the sender parameter:
- (void)methodName:(id *)sender {
switch ([sender tag]) {
//cases depending on tag
}
}

Related

Accessing Canvas from Subclass?

I am working with a C4 app, and have created a subclass of C4Shape. I am having trouble accessing the canvas from within the subclass but I'm not sure how to check it, or how to get access to it from another object.
This is the code I have so far:
#import "Platform.h"
#implementation Platform {
CGPoint o;
C4Timer *timer;
int speed;
}
-(void) setup {
speed = 10;
[self rect:CGRectMake(0, 0, 100, 100)];
timer = [C4Timer automaticTimerWithInterval:1.0f/30
target:self
method:#"push"
repeats:YES];
o = self.center;
}
+(id) platformWithRange:(CGRect)s {
Platform * bb = [Platform new];
bb.range = s;
return bb;
}
-(void) push {
// check boundaries
o.x-= speed;
if( 0 >= o.x - 50 ) {
o.x = range.size.width;
}
}
#end
Have a look at the second part of this answer: https://stackoverflow.com/a/15885302/1218605
You can create a property on your subclass into which you will set the canvas from the main workspace.
#implemenation C4WorkSpace
-(void)setup {
CustomSubclass *obj = [CustomSubclass new];
obj.canvas = self.canvas;
}
#end

Dynamic Accessibility Label for CALayer

How do I make a CALayer accessible? Specifically, I want the layer to be able to change its label on the fly, since it can change at any time. The official documentation's sample code does not really allow for this.
The following assumes that you have a superview whose layers are all of class AccessableLayer, but if you have a more complex layout this scheme can be modified to handle that.
In order to make a CALayer accessible, you need a parent view that implements the UIAccessibilityContainer methods. Here is one suggested way to do this.
First, have each layer own its UIAccessibilityElement
#interface AccessableLayer : CALayer
#property (nonatomic) UIAccessibilityElement *accessibilityElement;
#end
now in its implementation, you modify the element whenever it changes:
#implementation AccessableLayer
... self.accessibilityElement.accessibilityLabel = text;
#end
The AccessableLayer never creates the UIAccessibilityElement, because the constructor requires a UIAccessibilityContainer. So have the super view create and assign it:
#pragma mark - accessibility
// The container itself is not accessible, so return NO
- (BOOL)isAccessibilityElement
{
return NO;
}
// The following methods are implementations of UIAccessibilityContainer protocol methods.
- (NSInteger)accessibilityElementCount
{
return [self.layer.sublayers count];
}
- (id)accessibilityElementAtIndex:(NSInteger)index
{
AccessableLayer *panel = [self.layer.sublayers objectAtIndex:index];
UIAccessibilityElement *element = panel.accessibilityElement;
if (element == nil) {
element = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:self];
element.accessibilityFrame = [self convertRect:panel.frame toView:[UIApplication sharedApplication].keyWindow];
element.accessibilityTraits = UIAccessibilityTraitButton;
element.accessibilityHint = #"some hint";
element.accessibilityLabel = #"some text";
panel.accessibilityElement = element;
}
return element;
}
- (NSInteger)indexOfAccessibilityElement:(id)element
{
int numElements = [self accessibilityElementCount];
for (int i = 0; i < numElements; i++) {
if (element == [self accessibilityElementAtIndex:i]) {
return i;
}
}
return NSNotFound;
}

How could I get the property name of the current UITextField a user is in as a string?

I am using the following method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
Before, in order to find the current text field I was in, I was able to write something like this:
if (textField == self.textPlaceID)
{
//Do something
}
Is there a way to grab the name of my textField as a string? I am not asking to take what the user has typed in that textField, I'd like to be able to just get the property name of if. I need it to then concatenate it with some other strings. I am working on making a dynamic method call.
UITextFields do not have "names". You can give your text field a tag and use that.
Also, note that (pointer == pointer) will only return true if you are referencing the same objects, not equivalent values.
Here is how to use the tag: in Interface Builder, give each text field a tag, or if you create your text fields programmatically, set textField.tag = someInt; I usually use macros to make the code more readable:
#define kNameTextField 2
#define kAddressTextField 3
...
if (textField.tag == kNameTextField) ...
With lots of fields like that, I prefer enums:
typedef enum {
kNameTextField = 2,
kAddressTextField,
kPhoneTextField // etc
} Fields;
You can get name of property (in your case textField property) using this code:
-(NSString *)propertyName:(id)property {
unsigned int numIvars = 0;
NSString *key=nil;
Ivar * ivars = class_copyIvarList([self class], &numIvars);
for(int i = 0; i < numIvars; i++) {
Ivar thisIvar = ivars[i];
if ((object_getIvar(self, thisIvar) == property)) {
key = [NSString stringWithUTF8String:ivar_getName(thisIvar)];
break;
}
}
free(ivars);
return key;
}
Remember to import:
#import <objc/runtime.h>
Just call:
NSLog(#"name = %#", [self propertyName:self.textField]);
source
Primarily assign unique tags to each of the textFields (eg 1,2,3.....) avoid 0 for a textField tag
-(void)viewDidLoad{
NSDictionary *dictionary ; //declare it in .h interface
dictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"textPlaceID",[NSNumber numberWithInt:1], #"textPlaceID2",[NSNumber numberWithInt:2],nil]; // add textField as object and tag as keys
}
further..
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string{
NSString *textFieldPropertyName = [dictionary objectForKey:[NSNumber numberWithInt:textField.tag]];
}

How to add a binding programmatically for a NSTabView?

My application contains an NSTabView with two tabs. Further, the application itself has a playState which is an enum. The playState is kept in a Singleton.
typedef enum {
kMyAppPlayStatePlaying,
kMyAppPlayStatePaused
} MyAppPlayState;
The playState gets synthesized here.
#property (readwrite) MyAppPlayState playState;
I want to switch the NSTabView every time the playState changes. Therefore, I prepared an IBOutlet to add a binding similar to this one.
[self.playPauseTabView bind:#"selectedItemIdentifier" toObject:[MyAppState sharedState] withKeyPath:#"playState" options:nil];
I already recognized the identifier must be NSString. This does not match with my enum which is an int. I could maybe use an NSValueTransformer to fix this.
Further, selectedItemIdentifier does not exists. NSTabView only offers selectedTabViewItem which then allows to access identifier or label. Though, I cannot find a way to switch the item itself based on the identifer.
In situations like that, I find myself doing one of two things:
1) Register self (or some other object) as an observer of the property in question, and set the selected tab accordingly in -observeValueForKeyPath:ofObject:change:context:. It could look like this:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ( context == PlayStateChange )
{
if ( [[change objectForKey: NSKeyValueChangeKindKey] integerValue] == NSKeyValueChangeSetting )
{
NSNumber *oldValue = [change objectForKey: NSKeyValueChangeOldKey];
NSNumber *newValue = [change objectForKey: NSKeyValueChangeNewKey];
NSInteger oldInteger = [oldValue integerValue];
NSInteger newInteger = [newValue integerValue];
NSLog(#"Old play state: %ld, new play state: %ld", (long)oldInteger, (long)newInteger);
// Do something useful with the integers here
}
return;
}
}
2) declare a readonly NSString * property and declare that its value is affected by your playState property. Something like this:
#property (readonly) NSString *playStateStr;
// Accessor
-(NSString *)playStateStr
{
return playState == kMyAppPlayStatePlaying ? #"playing" : "paused";
}
+(NSSet *)keyPathsForValuesAffectingPlayStateStr
{
return [NSSet setWithObject: #"playState"];
}
Now you have an NSString-typed property that you can bind your tab view's selection.
I forgot to connect the NSTabView with its IBOutlet in the Interface Builder.
The following works for me.
NSDictionary* playStateOptions = [NSDictionary dictionaryWithObject:[[PlayStateValueTransformer alloc] init] forKey:NSValueTransformerBindingOption];
[self.playPauseTabView bind:#"selectedLabel" toObject:[MyAppState sharedState] withKeyPath:#"playState" options:playStateOptions];
In the NSValueTransformer I return an NSString which must be set in Interface Builder for each tab!

Get instance name of sender in objective-C

I want to get the name of a sender in Objective-C. For example, below I have a method which is called by an instance of UISlider in Interface Builder, I want to know what the instance name of it is so I can later add conditional blocks to the method for which instance of UISlider called the method.
e.g.
-(IBAction)sliderChanged:(UISlider *)sender {
//labAt1TimeRequired.text = [NSString stringWithFormat:#"%.1f", [sender value]];
NSLog(#"%#",sender);
Outputs:2010-10-15 22:46:02.257 EPC[3225:207] <UISlider: 0x495b140; frame = (205 3; 118 23); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x492e340>>
I want to be able to say
if(sender==myInstanceName) {
//do this
}
You could use
.tag member
to read an write and integer ID for the slider like this:
-(IBAction)sliderChanged:(UISlider
*)sender {
switch (sender.tag) {
case 0:
//SLider 0
break;
case 1:
//SLider 1
break;
default:
break;
}
}
Tag ID's can also be set for components in IB.
If your set on a string then you would need to subclass a UISlider.
You would use the tag property of UIView for identifying the sender.
-(IBAction)sliderChanged:(UISlider *)sender {
//labAt1TimeRequired.text = [NSString stringWithFormat:#"%.1f", [sender value]];
if (sender.tag == 1)
{
// do whatever
}
else
{
// do something else
}
}