Is there any alternative to use like tag to property of UIView? The thing is I'd like to pass UITextField some NSInteger. Way to do is tag. But I want to pass 2 different NSInteger.
Any ideas?
You could subclass UITextField and add two NSInteger properties to the class.
#interface CustomTextField : UITextField
#property (nonatomic, assign) NSInteger x;
#property (nonatomic, assign) NSInteger y;
#end
You can attach any data to any object using an Associative Reference. This is a very handy approach. It even correctly handles memory management. I sometimes use a category to wrap these so I can create new properties on an existing class. For example, in one project I'd like every view controller to know about a special label (like how they all know about navigationController). I do it this way:
#interface UIViewController (MYSpecialViewController)
#property (nonatomic, readwrite, strong) UILabel *specialLabel;
#end
#implementation UIViewController (MYSpecialViewController)
static const char kMySpecialLabelKey;
- (UILabel *)specialLabel
{
return objc_getAssociatedObject(self, &kMySpecialLabelKey);
}
- (void)setSpecialabel:(UILabel *)value
{
objc_setAssociatedObject(self, &kMySpecialLabelKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
You can find a simple working example using a UIAlertView in the iOS5:PTL sample code for Chapter 3.
Take the general, object-oriented solution, but remember you can a stuff lot of data into a tag:
- (uint32_t)pack:(uint16_t)a with:(uint16_t)b {
return (uint32_t)(a << 16 | b);
}
- (uint16_t)getA:(uint32_t)pair {
return (uint16_t)((pair & 0xffff0000) >> 16);
}
- (uint16_t)getB:(uint32_t)pair {
return (uint16_t)(pair & 0xffff);
}
// use it
- (void)setupSomeView {
someView.tag = [self pack:1024 with:2048];
}
- (IBAction)someControlEventHappened:(id)sender {
NSLog(#"%d %d", [self getA:sender.tag], [self getB:sender.tag]);
}
Caveats:
#RobNapier's answer is more general, more correct. The only
advantage this way is that it's quick and dirty
Works for pairs of unsigned ints < 32k
Works NSInteger implementations >= 32 bits, which is everywhere, I think.
Related
I'm developing an iPhone 4 application and I having problems with the class:
#interface Pattern : NSObject {
int maxNumShapes;
NSMutableArray* shapes;
NSMutableArray* shapeMatched;
CGSize bounds;
}
#property (nonatomic, retain, readonly) NSMutableArray* shapes;
#property (nonatomic, retain, readonly) NSMutableArray* shapeMatched;
...
- (void) setShapeMatched:(ShapeType)type;
#end
And its implementation:
- (void) setShapeMatched:(ShapeType)type {
int index = 0;
if (shapes != nil)
{
for(Object2D* obj in shapes)
{
if (obj.figure == type)
{
[shapeMatched replaceObjectAtIndex:index
withObject:[NSNumber numberWithBool:YES]];
obj.withFillColor = YES;
break;
}
else
index++;
}
}
}
I get the following warning:
Type of property 'shapeMatched' does not match type of accessor 'setShapeMatched:'
How can I fix this warning?
You method - (void)setShapeMatched:(ShapeType)type is probably intended to change something in the shapeMatched array, however, its name overwrites the setter of your property for that very same array.
It's unclear, but if you really want to overwrite the setter, the argument must be of type NSMutableArray * since that's the type of your property. Otherwise, if you method just do something else, rename it to avoid the collision. setShapeMatchedType:(ShapeType)t might be a good option.
You need to rename your custom setShapeMatched: to something else (like setMyShapeMatched). setShapeMatched: is already in use as the setter for your declared property.
I'm making an app that calculates certain things.
I need it to be able to take the input from the first textfields, for example 4+4 and save the result in a variable.
In the second text fields there could be 8+8 for example, and the result of that will also be saved into a variable (possibly the same).
Third row of textfields could yield more numbers etc, etc..
In the end there will be a button "Calculate" for example. And that will take the results from first, second, third etc textfields and calculate all of those together and output the end result.
The calculations are of course more advanced than this, but I just need the basic/simple idea of how to do this.
There is no need for saving the data to a file just now, it should just be in the app while the other textfields are being filled.
For 0x8badf00d:
Header.
#interface UnitConverterViewController : UIViewController {
NSMutableArray *calculationsArray;
UITextField *m1Text;
UITextField *m2Text;
}
#property (nonatomic, retain) IBOutlet UITextField *m1Text;
#property (nonatomic, retain) IBOutlet UITextField *m2Text;
#property (nonatomic, retain) IBOutlet NSMutableArray *calculationsArray;
#end
Implementation:
#implementation UnitConverterViewController
#synthesize m1Text, m2Text, calculationsArray;
#synthesize resultTotal = _resultTotal;
-(id)init {
if(self = [super init]){
calculationsArray = [[NSMutableArray alloc] init];
}
}
- (void)compute{
NSString* sumString = [NSString stringWithFormat:#"%d",[m1Text.text intValue]+[m2Text.text intValue]];
[calculationsArray addObject:sumString];
}
-(IBAction)calculate{
int total=0;
for(NSString* sumStr in calculationsArray){
total = total+[sumStr intValue];
}
NSLog(#"Total: %d", total);
[calculationsArray release], calculationsArray = nil;
}
I must be doing something wrong, and I know I need a way to output this, a label and such. But for now I need to know if what I've done so far is correct, and what the best way of outputting it would be.
You should declare the variables to store the results in your header file, these are than accessible from anywhere in your .m file, the same goes for your text fields.
For example:
Calculator.h
#interface Calculator: SuperclassName{
UITextField *_fldOne;
UITextField *_fldTwo;
UITextField *_fldThree;
UITextField *_fldFour;
int resultOne;
int resultTwo;
int _resultTotal;
}
#property(nonatomic, readonly) int resultTotal;
- (void) calculate;
#end
Calculator.m
#implementation Calculator
#synthesize resultTotal = _resultTotal;
- (void) calculate{
resultOne = [_fldOne.text intValue] * [_fldTwo.text intValue];
resultTwo = [_fldThree.text intValue] / [_fldFour.text intValue];
totalResult = resultOne + resultTwo;
}
#end
In this example resultOne and Two, and all the textfields are available throughout your class to work with, the totalResult is set as a readonly property and synthesized to create a getter automaticaly (which returns the value stored in _totalResult because of synchronizing like totalResult = _totalResult) as so it is available to read from outside the class.
As long as it all happens on one screen it should be more than enough, but of course you could make an NSDictionary or NSArray but that seems unnecessary here.
Hope this helps
Save the result to array. Lets say you have NSMutableArray* calculationsArray;//iVar
//initialize calculationsArray in init method
-(id)init
{
if(self = [super init])
{
calculationsArray = [[NSMutableArray alloc] init];
}
}
- (void)compute
{
NSString* sumString = [NSString stringWithFormat:#"%d",[textField1.text intValue]+[textField2.text intValue]);
[calculationsArray addObject:sumString];
}
- (IBAction)calculate
{
int total=0;
for(NSString* sumStr in calculationsArray)
{
total = total+[sumStr intValue];
}
NSLog(#"Total: %d",total);
[calculationsArray release],calculationsArray = nil;
}
OK, this is going to be a stupid question but anyway I have nowhere to ask it except here.
I have two buttons and there must be a switch-case statement performed on tapping any of them.
Of course I can put this statement in each IBAction code block but this code would look terribly.
I tried to put swith-case into a separate method and this is what I have:
.h file
#import <UIKit/UIKit.h>
#interface AppViewController : UIViewController
{
IBOutlet UILabel *someTextLabel;
NSNumber *current;
}
#property (nonatomic, retain) IBOutlet UILabel *someTextLabel;
#property (nonatomic, retain) NSNumber *current;
- (void) switchMethod;
- (IBAction) pressButtonForward;
- (IBAction) pressButtonBack;
#end
.m file
#import "AppViewController.h"
#implementation AppViewController
#synthesize someTextLabel;
#synthesize current;
current = 0;
- (void) switchMethod:current
{
switch((int)current) {
case 0:
//do something
break;
case 1 :
//do something
break;
//etc
default:
//do something
break;
}
}
- (IBAction) pressButtonBack
{
if((int)current == 0) {
current = 6;
}
else {
current--;
}
//here must be a switchMethod performed
}
- (IBAction) pressButtonForward
{
if((int)current == 6) {
current = 0;
}
else {
current++;
}
//here must be a switchMethod performed
}
//auto-generated code here
#end
Of course this code is incorrect but this is just like a blueprint of what I wanted to get.
Questions:
What is a correct way of using such switch-case statement as a separate method so that I could call it from IBAction methods?
How should I cast data types for this code to work, or would it be better to use integer type (for "current" variable) everywhere?
I haven't really got your question but maybe you should switch between forward and backward cases using a method like this :
- (IBAction)pressButton:(id) sender;
and depending on the value of sender, you can maybe switch case between Forward And Backward.
Thus, your code will be maybe more readable and you won't have to duplicate your switch.
N.B. : If your only problem is the duplication of your switch and if you don't want to use my method, I don't understand why you don't call directly your switchMethod in the two functions...
Answer to question 1:
just send a message to a self to invoke the switch method.
Answer to question 2:
NSNumber is an object that wraps a numeric value. To convert an NSNumber to an int:
int myIntValue = [number intValue];
To convert an int to a NSNumber
NSNumber* number = [NSNumber numberWithInt: myIntValue];
However, in your example, it's better to just define current as an int. So your code should look something like this:
#interface AppViewController : UIViewController
{
IBOutlet UILabel *someTextLabel;
unsigned int current;
}
#property (nonatomic, retain) IBOutlet UILabel *someTextLabel;
#property (nonatomic, assign) unsigned int current; // nonatomic might be redundant for POD types
- (void) switchMethod;
- (IBAction) pressButtonForward;
- (IBAction) pressButtonBack;
#end
#implementation AppViewController
#synthesize someTextLabel;
#synthesize current;
//current = 0; this wouldn't compile, in any case it is redundant, ivars start out as 0.
- (void) switchMethod
{
switch(current)
{
// do switchy stuff
}
}
- (IBAction) pressButtonBack
{
if(current == 0)
{
current = 6;
}
else
{
current--;
}
[self switchMethod];
}
- (IBAction) pressButtonForward
{
if(current == 6)
{
current = 0;
}
else
{
current++;
}
[self switchMethod];
}
// etc
#end
NB although I defined a property for current, I haven't used it in the code, which is a bit of a no-no. The main problem is that if anybody decides to observe current using KVO, they won't be notified of the changes. I should really have written things like
switch([self current])...
and
[self setCurrent: 6]...
etc
Hey there, I'm a designer thats really new to programming with xcode or Objective-C in general. I'm trying to create a few simple apps to try to get a better hang on programming the iPhone. Currently, I'm working on a very basic app which has 3 textfields, a name field and two number fields, and when you click the button, it shows in the label "name, the answer is answer" problem is, when i click the button, nothing is appearing in the label.
im pretty sure i have the code done right, i may be mistaken, i think i might have missed an outlet or something silly of the like. this is the part i get really lost on. any suggestions?
the .h:
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface fordaddyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
IBOutlet UITextField *name;
IBOutlet UITextField *myInt1;
IBOutlet UITextField *myInt2;
IBOutlet UILabel *sum;
IBOutlet UIButton *click;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
-(IBAction)click:(id)sender;
#end
the .m:
#import "fordaddyAppDelegate.h"
#implementation fordaddyAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window makeKeyAndVisible];
}
-(IBAction)click:(id)sender;
{
int sum;
sum = myInt1, myInt2;
NSLog (name, #", the answer is %i", sum);
}
- (void)dealloc {
[window release];
[super dealloc];
}
#end
and im terribly sorry in advance, the preview doesnt look to pretty :/
your problem is that you are just writting a message to the console, not displaying the result in the label...
Here's what it should be:
- (IBAction)click:(id)sender {
int sum = [myInt1.text intValue] + [myInt2.text intValue];
label.text = [NSString stringWithFormat:#"%# the answer is %d", name.text, sum];
}
That makes a variable 'sum' which is the result of the integer values of the text fields being added together. you access the string of a UITextView by using the .text. Then you have to convert it into an integer for addition, so you call the intValue method on it. You then make an NSString with stringWithFormat, and have it contain the name.text and the sum. I would highly recommend doing some more reading about Objective-C in general before you start with all this GUI stuff... just a suggestion.
Your problem is this:
int sum;
sum = myInt1, myInt2;
sum is an integer. myInt1 and myInt2 are UITextFields. The comma does not do what you're expecting.
You need to extract the intValue from each of the textfields, and add them together using a "+" (just like you would with regular math).
I am very new to objective-c and having a problem to initialize an object in view controller. The problem I am having is that when setTemp method is called, "0" is printed on the screen instead of the value of cTemp I would like it to be. Can anyone help me on this problem?
Below are excerpts of the code I have.
SJT.h
#import <Foundation/Foundation.h>
#import <stdlib.h>
#interface SJT : NSObject {
int cTemp;
}
- (int) newTemp;
#end
SJT.m
#import "SJT.h"
#implementation SJT
- (int) newTemp
{
cTemp = 25 + rand() % 8;
return cTemp;
}
#end
SJTViewController.h
#import <UIKit/UIKit.h>
#class SJT;
#interface SJTViewController : UIViewController {
IBOutlet UILabel *temp;
SJT *sjt;
}
#property (retain, nonatomic) UILabel *temp;
#property (retain, nonatomic) SJT *sjt;
- (IBAction) setTemp: (id) sender;
#end
SJTViewController.m
#import "SJTViewController.h"
#import "SJT.h"
#implementation SJTViewController
#synthesize temp;
#synthesize sjt;
- (IBAction) setTemp: (id) sender
{
NSString *tempText = [[NSString alloc] initWithFormat:#"%d",sjt.newTemp];
temp.text = tempText;
[tempText release];
}
.
.
.
#end
The problem is that you're mistaking property syntax for a method call; i.e.
sjt.newTemp
would become a call to [sjt newTemp]. Which happens to be exactly what you want, except that you have not specified in your header/implementation that there actually is a property called newTemp.
So, in this scenario what you want to do is either a) define the property in the header:
#property(nonatomic, readonly) int newTemp;
or b), just call the method newTemp:
[sjt newTemp]
Are you certain that sjt is not nil? You don't provide the code where and instance of SJT is constructed. In Objective-C you can call a method on a nil reference without error, and if you do so on a method that returns an int it will return 0.
So sjt.newTemp will return 0 if sjt is nil.
Both Jacob and teabot have pointed out valid possible reasons -- which one is correct (or both!) depends on pieces of code we can't see in your post.
Based on what you've written so far, you might not be thinking of newTemp as a property, but more as a function call, so I would suggest changing your code to:
- (IBAction) setTemp: (id) sender {
int tempInt = [self.sjt newTemp];
self.temp.text = [NSString stringWithFormat:#"%d", tempInt];
}
which is functionally equivalent. Note the convenience constructor stringWithFormat: returns an autoreleased object, which is then retained by the retain property text of the temp UILabel.
The other thing to double-check in your code is that self.sjt is not nil, which is exactly what teabot said. Objective-C returns 0 on method calls invoked on a nil pointer.