Pointer that can reference a UITextView or a UITextField - objective-c

I want to print a form that contains a mixture of UITextFields and UITextViews, doing exactly the same thing with each one regardless of its actual type. To keep the code clean I'd like to assign each item in the views array to the same variable in order to retrieve its printing parameters. I thought I could do this with a variable of type id, but I haven't hit on anything that will compile. The code below doesn't compile but it shows what I want to do. My thanks to anyone who tells me how to do this correctly.
id theField;
//for each field on the page
for (j = offsetToFirstFormField; j < [self.fields count]; j++) {
theField = [self.fields objectAtIndex: j];
printStr = theField.text;
if ([printStr length] > 0) {
theFont = [theField font];
maxSize = CGSizeMake(theField.frame.size.width, theField.frame.size.height);
printStrSize = [printStr sizeWithFont:theFont constrainedToSize:maxSize lineBreakMode:UILineBreakModeClip];
printRect = CGRectMake((theField.frame.origin.x * xScale) + xOffset, (theField.frame.origin.y * yScale) + yOffset, printStrSize.width, printStrSize.height);
[printStr drawInRect:printRect withFont:theFont];
}
}

You can't use dot-syntax with id variables. You have to stick with message-sending syntax. For example, you have to change this:
printStr = theField.text;
to this:
printStr = [theField text];
If that doesn't fix it, edit your question and paste in the actual error messages you're getting.

Encapsulate your printable functionality in a protocol. So you will be using id<Printable> rather than id. Your protocol will have methods like getText getFont. Or you can use category to extend the existing classes.

Related

Converting a string variable from Binary to Decimal in Objective C

Im trying to create a Binary to Decimal calculator and I am having trouble doing any sort of conversion that will actually work. First off Id like to introduce myself as a complete novice to objective c and to programming in general. As a result many concepts will appear difficult to me, so I am mostly looking for the easiest way to understand and not the most efficient way of doing this.
I have at the moment a calculator that will accept input and display this in a label. This part is working fine and I have no issues with it. The variable that the input is stored on is _display = [[NSMutableString stringWithCapacity:20] retain];
this is working perfectly and I am able to modify the data accordingly. What I would like to do is to be able to display an NSString of the conversion in another label. At the moment I have tried a few solutions and have not had any decent results, this is the latest attempt
- (NSMutableString *)displayValue2:(long long)element
{
_str= [[NSMutableString alloc] initWithString:#""];
if(element > 0){
for(NSInteger numberCopy = element; numberCopy > 0; numberCopy >>= 1)
{
[_str insertString:((numberCopy & 1) ? #"1" : #"0") atIndex:0];
}
}
else if(element == 0)
{
[_str insertString:#"0" atIndex:0];
}
else
{
element = element * (-1);
_str = [self displayValue2:element];
[_str insertString:#"0" atIndex:0];
NSLog(#"Prima for: %#",_str);
for(int i=0; i<[_str length];i++)
_str = _display;
NSLog(#"Dopo for: %#",_str);
}
return _str;
}
Within my View Controller I have a convert button setup, when this is pressed I want to set the second display field to the decimal equivalent. This is working as if I set displayValue2 to return a string of my choosing it works. All I need is help getting this conversion to work. At the moment this bit of code has led to "incomplete implementation" being displayed at the to of my class. Please help, and cheers to those who take time out to help.
So basically all you are really looking for is a way to convert binary numbers into decimal numbers, correct? Another way to think of this problem is changing a number's base from base 2 to base 10. I have used functions like this before in my projects:
+ (NSNumber *)convertBinaryStringToDecimalNumber:(NSString *)binaryString {
NSUInteger totalValue = 0;
for (int i = 0; i < binaryString.length; i++) {
totalValue += (int)([binaryString characterAtIndex:(binaryString.length - 1 - i)] - 48) * pow(2, i);
}
return #(totalValue);
}
Obviously this is accessing the binary as a string representation. This works well since you can easily access each value over a number which is more difficult. You could also easily change the return type from an NSNumber to some string literal. This also works for your element == 0 scenario.
// original number wrapped as a string
NSString *stringValue = [NSString stringWithFormat:#"%d", 11001];
// convert the value and get an NSNumber back
NSNumber *result = [self.class convertBinaryStringToDecinalNumber:stringValue];
// prints 25
NSLog(#"%#", result);
If I misunderstood something please clarify, if you do not understand the code let me know. Also, this may not be the most efficient but it is simple and clean.
I also strongly agree with Hot Licks comment. If you are truly interested in learning well and want to be an developed programmer there are a few basics you should be learning first (I learned with Java and am glad that I did).

What is the most efficient way to move NSArray objects to UITextFields?

I have some code where there may or may not be objects in the Array... this is the code I am dealing with:
oServices1.text = CustomServicesArray[0];
oServices2.text = CustomServicesArray[1];
oServices3.text = CustomServicesArray[2];
oServices4.text = CustomServicesArray[3];
oServices5.text = CustomServicesArray[4];
oServices6.text = CustomServicesArray[5];
oServices7.text = CustomServicesArray[6];
oServices8.text = CustomServicesArray[7];
oServices9.text = CustomServicesArray[8];
oServices10.text = CustomServicesArray[9];
oServices11.text = CustomServicesArray[10];
oServices12.text = CustomServicesArray[11];
oServices13.text = CustomServicesArray[12];
oServices14.text = CustomServicesArray[13];
oServices15.text = CustomServicesArray[14];
oServices16.text = CustomServicesArray[15];
oServices17.text = CustomServicesArray[16];
oServices18.text = CustomServicesArray[17];
oServices19.text = CustomServicesArray[18];
oServices20.text = CustomServicesArray[19];
oServices21.text = CustomServicesArray[20];
oServices22.text = CustomServicesArray[21];
oServices23.text = CustomServicesArray[22];
Rather than check each and every array object for nil, is there a way I can take the oServices*xx*.text UIFields and put them into some kind of array so I can just use a loop?
Are you aware of reflexivity? With KVC you could save up much code and time:
for(int i=1; i<=23; i++) {
NSString* key= [NSString stringWithFormat: #"oServices%d"i];
// Remember that variables should start with a lowercase letter
[[self valueForKey: key] setText: customServicesArray[i-1] ];
}
But if you don't want to bind all these variables in your storyboard/xib file (even this may be too much), just set the tag of each text field in the order that you want (from 1), so that you can get them back using viewWithTag:
// From the UIViewController
for(int i=1; i<=23; i++) { // Consider defining a constant instead of 23
[[self.view viewWithTag: i] setText: customServicesArray[i-1] ];
}
I consider this last solution better because you avoid binding so many variables.
You can use an OutletCollection to hold oServices and loop on that. Note however that outlet collections are not sorted so you would need to sort them beforehand (on the tag criteria, or location for example).
For ordering see this question.
Set the tag property of the UITextFields to their corresponding ordinal in the array. The default value of tag is 0, so you may need to set the tag property to ordinal + 1 if there are other views in the parent view of your UITextFields. On the parent view of your text fields, you can use the viewWithTag: method to retrieve the appropriate UITextField.

How to add 1 to Variable with Button Click?

I want to add 1 to my variable each time the button is clicked, but instead a 10 digit number appears. What am I doing wrong with the code below?
-(IBAction)recordData:(id)sender {
int randomNumber;
randomNumber = randomNumber + 1;
NSString *myRandomNumber = [NSString stringWithFormat:#"%i", randomNumber];
NSString *CompleteData = [[NSString alloc] initWithFormat:DataView.text];
CompleteData = [CompleteData stringByAppendingString: #"\n"];
CompleteData = [CompleteData stringByAppendingString:myRandomNumber];
DataView.text = CompleteData;
}
Make
int randomNumber
either static or declare it as an instance variable.
What you are currently doing is creating a new varialbe each time when recordData is invoked. Plus you do not initialize it. Local variables are not initialized. Instance variables are initialized with 0/nil. As a result your variable has some random content (as its name suggests anyway :). To that random value you add 1.
Your variable is not initialised: int randomNumber = 0 would fix that.
randomNumber's scope is the recordData: method. You could make it a static variable a suggested by holex, or even better, make it a property of your class.
Have a look at Encapsulating Data in Apple's Objecitve-c Documentation to learn more about iVars and properties.

interacting with UIViews stored inside a NSMutableArray

a big noob needs help understanding things.
I have three UIViews stored inside a NSMutableArray
lanes = [[NSMutableArray arrayWithCapacity:3] retain];
- (void)registerLane:(Lane*)lane {
NSLog (#"registering lane:%i",lane);
[lanes addObject:lane];
}
in the NSLog I see: registering lane:89183264
The value displayed in the NSLog (89183264) is what I am after.
I'd like to be able to save that number in a variable to be able to reuse it elsewhere in the code.
The closest I could come up with was this:
NSString *lane0 = [lanes objectAtIndex:0];
NSString *description0 = [lane0 description];
NSLog (#"description0:%#",description0);
The problem is that description0 gets the whole UIView object, not just the single number (dec 89183264 is hex 0x550d420)
description0's content:
description0:<Lane: 0x550d420; frame = (127 0; 66 460); alpha = 0.5; opaque = NO; autoresize = RM+BM; tag = 2; layer = <CALayer: 0x550d350>>
what I don't get is why I get the correct decimal value with with NSLog so easily, but seem to be unable to get it out of the NSMutableArray any other way. I am sure I am missing some "basic knowledge" here, and I would appreciate if someone could take the time and explain what's going on here so I can finally move on. it's been a long day studying.
why can't I save the 89183264 number easily with something like:
NSInteger * mylane = lane.id;
or
NSInteger * mylane = lane;
thank you all
I'm really confused as to why you want to save the memory location of the view? Because that's what your '89183264' number is. It's the location of the pointer. When you are calling:
NSLog (#"registering lane:%i",lane);
...do you get what's actually being printed out there? What the number that's being printed means?
It seems like a really bad idea, especially when if you're subclassing UIView you've already got a lovely .tag property which you can assign an int of your choosing.
You're making life infinitely more complex than it needs to be. Just use a pointer. Say I have an array containing lots of UIViews:
UIView *viewToCompare = [myArray objectAtIndex:3];
for (id object in myArray) {
if (object == viewToCompare) {
NSLog(#"Found it!");
}
}
That does what you're trying to do - it compares two pointers - and doesn't need any faffing around with ints, etc.

Objective-C modify parameter to method at runtime

I'd like to change the value of a parameter at runtime and curious how this works in Obj-C.
I have a loop where value of 'n' is 0 increasing by 1 with each loop. How does one increment the passed parameter by 1 as n moves.
UIViewSubclass *uiViewSubclass = [[UIViewSubclass alloc] initWithValue:([value integerValue])
andPlacement:kPlacement0;
next time through loop I'd like 2nd argument to read as: andPlacement:kPlacement1;
and then: andPlacement:kPlacement2; and on...
do I make kPlacement a string and stringByAppendingString:[[NSNumber numberWithInt:n] stringValue]; ?
What's the Obj-C/Cocoa approach?
You can't modify your source code or make up variable references at runtime. Objective-C isn't that dynamic.
If the values of kPlacement0 through kPlacementMax are sequential, you may be able to use a for loop to step through them directly:
for (MyPlacement placement = kPlacement0; placement += kPlacementIncrement; placement <= kPlacementMax) {
UIViewSubclass *instanceOfUIViewSubclass = [[UIViewSubclass alloc] initWithValue:([value integerValue])
andPlacement:placement];
//Do something with instanceOfUIViewSubclass.
[instanceOfUIViewSubclass release];
}
(You will need to define kPlacementIncrement and kPlacementMax in addition to the kPlacement0, etc. constants. I'm using MyPlacement as the name of your enumeration type that the kPlacement0 etc. constants correspond to.)
If they are not sequential, put them in a C array and iterate on that array:
enum { numPlacements = <#Insert the number of placement constants here#> };
MyPlacement placements[numPlacements] = {
kPlacement0,
kPlacement1,
kPlacement2,
⋮
}
for (unsigned i = 0U; i < numPlacements; ++i) {
UIViewSubclass *instanceOfUIViewSubclass = [[UIViewSubclass alloc] initWithValue:([value integerValue])
andPlacement:placements[i]];
//Do something with instanceOfUIViewSubclass.
[instanceOfUIViewSubclass release];
}
You probably can come up with more-descriptive names than kPlacement0 etc. When you want to refer to them by number, do that; when you want to refer to them by name, give them good names.