Calculator label string displaying - objective-c

I'm new to Objective-C and trying to make a calculator. My problem is I can't add the new number when button is pressed to the string no matter what I use (I tried methods appendString/Format and stringByAppendingString/Format).
Inputting numbers. I do the same for every other numbers:
- (IBAction)btn9:(id)sender {
[self tabbedNumber:9];
}
Declare the variable:
#property NSString *labelString;
Getting the number function:
-(void)tabbedNumber:(int)num{
NSString *lblStr = [[NSString alloc]init];
lblStr = [lblStr stringByAppendingString:[#(num) stringValue]];
self.labelString = lblStr;
[self updateText];
}
Displaying on calculator with a label calLabel:
- (void)updateText{
self.calLabel.text = self.labelString;
Best Anwser by #pavelTerziyski:
You keep lblStr = [lblStr stringByAppendingString:[#(num) stringValue]] in the function but the creation of the variable must be in the view didLoad - (void)viewDidLoad { [super viewDidLoad]; self.lblStr = [NSString new]; }

How you get the (int)num - because i tried your code with this and it worked perfectly fine
- (IBAction)buttonAction:(UIButton *)sender {
NSString *lblStr = [[NSString alloc]init];
lblStr = [lblStr stringByAppendingString:sender.titleLabel.text];
self.labelString = lblStr;
[self updateText];
}
- (void)updateText{
self.numberLabel.text = self.labelString;
}

Try this method 👇
- (IBAction)tabbedNumber:(UIButton *)sender{
self.labelString.text = [self.labelString.text stringByAppendingString:sender.titleLabel.text];
}
With this you can add any button's title label text to your label string.
But you should connect number buttons to this method.
if you want to update label with another method try this 👇
- (IBAction)tabbedNumber:(UIButton *)sender{
[self updateText:sender.titleLabel.text];
}
- (void)updateText:(NSString *)tappedNumberString{
self.labelString.text = [self.labelString.text stringByAppendingString:tappedNumberString];
}
Don't forget to connect tabbedNumber method to number Buttons.

Appending something to a new created string is not very useful.
You need to append the integer (as text) to the property labelString which seems to hold the actual value of the label.
-(void)tabbedNumber:(int)num{
self.labelString = [self.labelString stringByAppendingFormat:#"%i", num];
[self updateText];
}

Related

NSMutableDictionary - entries appear to be over-written by each addition

I'm fairly new to Objective-C; but have been coding for years and this one really stumps me.
I'm trying to build an iPhone app and wanted to create a "settings" screen which will use a Table format. (Xcode 5.1.1).
I want to future proof the main Settings screen and make it easy for the application coding by hiding the "hard work" in subroutines/methods.
I may be getting too clever but I've created a class for each 'setting' that contains screen prompts, default values etc and using an Enum to cross-reference it (so the compiler will highlight typos etc)
The problem I'm encountering is that when I add entries to my NSMutableDictionary and use lldb to print the values; every entry seems to have the same "key" and values. I've tried converting the eNum to an NSNumber and also as an NSString -- no difference in the result - so I'm obviously doing something else daft but just can't see it
The following code is from various .m & .h files, I've omitted boring stuff that you always "have to have" to keep it short
// basic x-ref I want to use in my code
typedef NS_OPTIONS(NSInteger, ConfigurationType) {
unDefined = -1,
Server = 0,
Id = 1,
Phone = 2
};
// definition for a "single" Settings value
#interface SettingDefinition : NSObject
#end
#implementation SettingDefinition
ConfigurationType _cfgType;
NSString *_cfgName;
NSString *_screenTitle;
NSString *_value;
- (NSString *)description
{
NSString *className = NSStringFromClass([self class]);
return [NSString stringWithFormat:#"<%#: x%p Type=%d dbKey=%# '%#' -> %#>", className, self, _cfgType, _cfgName, _screenTitle, _value];
}
- (id)initType:(ConfigurationType)cfgOption
withDbKey: (NSString*)dbKey
asOptionTitle:(NSString*)cfgTitle
withValue:(NSString*)itmValue
{
self = [super init];
if (self) {
_screenTitle = cfgTitle;
_cfgName = dbKey;
_cfgType = cfgOption;
_value = itmValue;
}
return self;
}
#end
#interface Configuration : NSObject
#end
#implementation Configuration {
NSMutableDictionary *Settings; // List of Setting structures
};
- (id)init {
self = [super init];
if (self) {
Settings = [[NSMutableDictionary alloc]init];
[self add:Server withDbKey:#"Server" asOptionTitle:#"Server"];
[self add:Id withDbKey:#"Id" asOptionTitle:#"Your ID"];
[self add:Phone withDbKey:#"Phone" asOptionTitle:#"Phone No."];
}
return self;
}
- (void) add:(ConfigurationType)cfgOption
withDbKey:(NSString*)dbKey
asOptionTitle:(NSString*)cfgTitle
{
NSString * itmValue = [self configurationValue: cfgOption cfgName:dbKey];
SettingDefinition *x = [[SettingDefinition alloc]
initType: cfgOption
withDbKey: dbKey
asOptionTitle: cfgTitle
withValue: itmValue];
[Settings setObject:x forKey:[self asKey:cfgOption]];
}
- (NSString *) asKey:(ConfigurationType) settingType {
NSString *rc = [NSString stringWithFormat:#"%d", settingType];
return rc;
}
- (NSString *) configurationValue:(ConfigurationType) settingType {
// returns a suitable value from my system setup
// which is initially a null value until the user sets everything up
}
the debug window shows the following when I break after the final call to [self add: ...]
(lldb) po Settings
{
0 = "<SettingDefinition: x0x8e7c280 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
1 = "<SettingDefinition: x0x8c703a0 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
2 = "<SettingDefinition: x0x8e7c310 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
}
The (null) is obviously due to no data in 'value' yet; but why do they all show as 'Phone'; if I break after the second call to [self add:..] they all show as 'Id'
UPDATE:
DOH! obviously they're globals (I've been using another IDE where everything is local until exposed) .. If I enclose them in braces in the implementation as the documentation states then the exhibited problem vanishes. I have properties to access the variables but as the setter does more than just set the memory, I thought I'd need my "own" variables to hold the data.. said it was something daft .. thank you!

Get label.text from UILabel in an instance method iOS 7

I have a pickerview that displays an array of locations (2 components); below that are 2 UILabels (2 under each component).
When a user opens the app, the picker defaults to the first object in each array in the picker components and changes the label below to reflect that selection.
So it would look something like this:
|PickerComponent1|PickerComponent2|
| Label 1 | Label 2 |
It displays the labels correctly when [viewDidLoad] is called. The labels changed to the appropriate names.
I created an instance method - but I can't pass the text value of the labels to that method.
The log displays (null) and it's coming back as empty.
Any ideas on how I can pass that label text to the method appropriately?
*edit: if I put that code that assigned label1 and the NSLog line into the viewDidLoad method it prints out the label text appropriately. When I put it into the method it does not.
My viewDidLoad in my .m file:
- (void)viewDidLoad
{
//set self as delegate for tripPicker
_tripPicker.delegate = self;
//Set size of tripPicker & datePicker
_tripPicker.transform = CGAffineTransformMakeScale(0.60, 0.60);
_datePicker.transform = CGAffineTransformMakeScale(0.60, 0.60);
//Call method to get array of school names (reusable)
MetaMiles *model = [MetaMiles schoolNameList];
_schoolArray1 = (NSArray *)model;
_schoolArray2 = (NSArray *)model;
//Set date to current date
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"MM/dd/yyyy"];
_dateLabel.text = [NSString stringWithFormat:#"Date of trip: %#",[dateFormatter stringFromDate:self.datePicker.date ]];
//Set selector method for datePicker so on the value change it updates the date
[self.datePicker addTarget:self action:#selector(updateLabelForDate:) forControlEvents:UIControlEventValueChanged];
[super viewDidLoad];
//Set labels to be appropriate schools
begSchoolLabel.text = [_schoolArray1 objectAtIndex:[_tripPicker selectedRowInComponent:0]];
endSchoolLabel.text = [_schoolArray2 objectAtIndex:[_tripPicker selectedRowInComponent:1]];
//Update the Mileage indicator to display miles between currently selected values
ML54AddMilesViewController *milesObject = [[ML54AddMilesViewController alloc]init];
NSArray *currentMiles = [milesObject getMileage];
NSLog(#"Current Miles first run: %#",currentMiles);
}
My getMileage method:
- (NSArray *)getMileage {
//Update the Mileage indicator to display miles between currently selected values
NSString *begSchool = begSchoolLabel.text;
NSLog(#"FIRE THIS OFF : %#",begSchool);
NSString *endSchool = endSchoolLabel.text;
NSPredicate *milesFilter = [NSPredicate predicateWithFormat:#"beg_school=%# AND end_school=%#", begSchool, endSchool];
NSArray *resultMiles = [MetaMiles MR_findAllWithPredicate:milesFilter];
if (!resultMiles || ![resultMiles count]) {
NSLog(#"Empty Array");
} else {
NSLog(#"Our array is: %#", [resultMiles objectAtIndex:0]);}
return resultMiles;
}
What I ended up doing was instead of using the label to get the text - I just had it nab whatever the picker had chosen. The label updates appropriately but for some reason I couldn't pass it between methods - this other way I was able to do that.

UITEXTVIEW: Get the recent word typed in uitextview

I want to get the most recent word entered by the user from the UITextView.
The user can enter a word anywhere in the UITextView, in the middle or in the end or in the beginning. I would consider it a word when the user finishes typing it and presses a space and does any corrections using the "Suggestions from the UIMenuController".
Example: User types in "kimd" in the UITextView somewhere in the middle of text, he gets a popup for autocorrection "kind" which he does. After he does that, I want to capture "kind" and use it in my application.
I searched a lot on the internet but found solutions that talk about when the user enters text in the end. I also tried detecting a space and then doing a backward search until another space after some text is found, so that i can qualify it as a word. But I think there may be better ways to do this.
I have read somewhere that iOS caches the recent text that we enter in a text field or text view. If I can pop off the top one , that's all I want. I just need handle to that object.
I would really appreciate the help.
Note: The user can enter text anywhere in UItextview. I need the most recent entered word
Thanks.
//This method looks for the recent string entered by user and then takes appropriate action.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
//Look for Space or any specific string such as a space
if ([text isEqualToString:#" "]) {
NSMutableCharacterSet *workingSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
NSRange newRange = [self.myTextView.text rangeOfCharacterFromSet:workingSet
options:NSBackwardsSearch
range:NSMakeRange(0, (currentLocation - 1))];
//The below code could be done in a better way...
UITextPosition *beginning = myTextView.beginningOfDocument;
UITextPosition *start = [myTextView positionFromPosition:beginning offset:currentLocation];
UITextPosition *end = [myTextView positionFromPosition:beginning offset:newRangeLocation+1];
UITextRange *textRange = [myTextView textRangeFromPosition:end toPosition:start];
NSString* str = [self.myTextView textInRange:textRange];
}
}
Here is what I would suggest doing, might seem a little hacky but it would work just fine:
First in .h conform to the UITextViewDelegate and set your text view's delegate to self like this:
myTextView.delegate = self;
and use this code:
- (void)textViewDidChange:(UITextView *)textView { // Delegate method called when any text is modified
if ([textView.text substringFromIndex: [textView.text length] - 1]) { // Gets last character of the text view's text
NSArray *allWords = [[textView text] componentsSeparatedByString: #" "]; // Gets the text view's text and fills an array with all strings seperated by a space in text view's text, basically all the words
NSString *mostRecentWord = [allWords lastObject]; // The most recent word!
}
}
I use this code to get the word behind the #-sign:
- (void)textViewDidChange:(UITextView *)textView {
NSRange rangeOfLastInsertedCharacter = textView.selectedRange;
rangeOfLastInsertedCharacter.location = MAX(rangeOfLastInsertedCharacter.location - 1,0);
rangeOfLastInsertedCharacter.length = 1;
NSString *lastInsertedSubstring;
NSString *mentionSubString;
if (![textView.text isEqualToString:#""]) {
lastInsertedSubstring = [textView.text substringWithRange:rangeOfLastInsertedCharacter];
if (self.startOfMention > 0 || self.startOfHashtag > 0) {
if ([lastInsertedSubstring isEqualToString:#" "] || (self.startOfMention > textView.selectedRange.location || self.startOfHashtag > textView.selectedRange.location)) {
self.startOfMention = 0;
self.lenthOfMentionSubstring = 0;
}
}
if (self.startOfMention > 0) {
self.lenthOfMentionSubstring = textView.selectedRange.location - self.startOfMention;
NSRange rangeOfMentionSubstring = {self.startOfMention, textView.selectedRange.location - self.startOfMention};
mentionSubString = [textView.text substringWithRange:rangeOfMentionSubstring];
dhDebug(#"mentionSubString: %#", mentionSubString);
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
}
}
}
Simple extension for UITextView:
extension UITextView {
func editedWord() -> String {
let cursorPosition = selectedRange.location
let separationCharacters = NSCharacterSet(charactersInString: " ")
let beginRange = Range(start: text.startIndex.advancedBy(0), end: text.startIndex.advancedBy(cursorPosition))
let endRange = Range(start: text.startIndex.advancedBy(cursorPosition), end: text.startIndex.advancedBy(text.characters.count))
let beginPhrase = text.substringWithRange(beginRange)
let endPhrase = text.substringWithRange(endRange)
let beginWords = beginPhrase.componentsSeparatedByCharactersInSet(separationCharacters)
let endWords = endPhrase.componentsSeparatedByCharactersInSet(separationCharacters)
return beginWords.last! + endWords.first!
}
}

NSNumberformatter quasi Scientific notations

I need the NSNumberFormatter to conditionally display very huge or very small numbers as Scientific notation. But if the number can be presented without, i need it to be only decimal.
6.62e-34 is Ok, but 4,2E1 is not.
Elsewhere in the system, I have solved this using the following method:
- (NSString *) formatNumber: (double) d {
BOOL sci=NO;
double dd = d;
if (dd<0.0) dd=(-d);
if ((dd>0.0) && (dd<1e-3)) sci=YES;
if (dd>1e+8) sci=YES;
if (sci) [nf setNumberStyle:NSNumberFormatterScientificStyle];
else [nf setNumberStyle:NSNumberFormatterDecimalStyle];
return [nf stringFromNumber:[NSNumber numberWithDouble:d]];
}
But at this particular place, the whole thing is set up in the interface builder, with bindings to an managed object modell and using an array controller object. In the first text cell of the colum in the tableview, I have dragged in the numberformatter. I dont know if its possible to define some custom methods to be called to do the formatting, instead of using this NumberFormatter. If I take it away, I got errors when I run it.
anyone have some idea ?
What you want to do is write a subclass of NSValueTransformer. You can then provide the name of that transformer class in IB, in the bindings inspector. Here is an example:
#implementation RDTransformer
- (id)init {
if (self = [super init]) {
self.formatter = [[NSNumberFormatter alloc] init];
[self.formatter setNumberStyle:NSNumberFormatterScientificStyle];
[self.formatter setMaximumFractionDigits:3];
}
return self;
}
+(Class)transformedValueClass {
return [NSString class];
}
+(BOOL)allowsReverseTransformation {
return NO;
}
-(id)transformedValue:(NSNumber *)value {
if ([value compare:#1000] == NSOrderedAscending) {
return value.stringValue;
}else{
return [self.formatter stringFromNumber:value];
}
}
In IB, the column (in a single column table) has its value bound to Array Controller.arrangedObjects with a value transformer of RDTransformer. I don't have any formatters connected to the table cells.

After xcode crash some buttons have either empty titles or are partially truncated

This seems to be a partial repost of XCode 4: some button titles not visible in iOS simulation but their question wasn't answered.
Please be gentle, I'm very new to this.
I've implemented a stack-based calculator program as per the stamford lecture series, but some of my buttons show as either empty or half truncated in the simulator. The same buttons will do it every time I run the sim, but if I move any buttons around it changes which ones are affected. It's usually the bottom ones.
First example here: http://i.imgur.com/YpC1f.png - see how the bottom row of buttons don't display correctly? If I make any one of those buttons taller, it will show with no title but all the other four buttons will then show correctly.
I thought it might be too close to the bottom, or those buttons were broken, or similar. So I deleted the whole bottom row, made everything smaller, and then recreated those buttons and now I get four buttons with blank titles and two truncated: http://i.imgur.com/kM1Rb.png
Note that the buttons all still work as expected, it's just the display that isn't right.
Am I doing something wrong? Any advice appreciated.
EDIT: Full code from the controller:
#import "CalculatorViewController.h"
#import "CalculatorBrain.h"
#interface CalculatorViewController()
#property (nonatomic) BOOL userIsInTheMiddleOfEnteringANumber;
#property (nonatomic, strong) CalculatorBrain *brain;
- (void)updateStackDisplay:(NSString *)value;
#end
#implementation CalculatorViewController
#synthesize display = _display;
#synthesize stackDisplay = _stackDisplay;
#synthesize userIsInTheMiddleOfEnteringANumber = _userIsInTheMiddleOfEnteringANumber;
#synthesize brain = _brain;
- (CalculatorBrain *)brain {
if (!_brain) _brain = [[CalculatorBrain alloc] init];
return _brain;
}
- (void)updateStackDisplay:(NSString *)value {
// if there's nothing sent so far, just initialise it
if (self.stackDisplay.text.length == 0) {
self.stackDisplay.text = value;
return;
}
// This part is a little confusing. Extra assignment asked for = to be added to the end of the stack label if an operation was pressed.
// Here I check for = at the end of the label and remove it so it's only displayed once. If "=" is being passed (done by the operation itself), it will be added back on right at the end of this function.
if ([self.stackDisplay.text rangeOfString:#"="].location == (self.stackDisplay.text.length - 1)) {
// .location starts at zero, .length doesn't.
self.stackDisplay.text = [self.stackDisplay.text substringToIndex:[self.stackDisplay.text length]-1];
}
// If we add a space after remove the = we'll end up with double space. Hence the else if, not if.
else if (!self.userIsInTheMiddleOfEnteringANumber) {
self.stackDisplay.text = [self.stackDisplay.text stringByAppendingString:#" "];
}
self.stackDisplay.text = [self.stackDisplay.text stringByAppendingString:value];
}
- (IBAction)digitPressed:(UIButton *)sender {
NSString *digit = sender.currentTitle;
if ([digit isEqualToString:#"."]) {
if ([self.display.text rangeOfString:#"."].location != NSNotFound) {
return;
}
else {
if (!self.userIsInTheMiddleOfEnteringANumber) digit = #"0.";
}
}
[self updateStackDisplay:digit];
if (self.userIsInTheMiddleOfEnteringANumber) {
self.display.text = [self.display.text stringByAppendingString:digit];
}
else {
self.display.text = digit;
self.userIsInTheMiddleOfEnteringANumber = YES;
}
}
- (IBAction)operationPressed:(UIButton *)sender {
if (self.userIsInTheMiddleOfEnteringANumber) [self enterPressed];
[self updateStackDisplay:sender.currentTitle];
[self updateStackDisplay:#"="];
double result = [self.brain performOperation:sender.currentTitle];
NSString *resultString = [NSString stringWithFormat:#"%g", result];
self.display.text = resultString;
}
- (IBAction)enterPressed {
if (self.userIsInTheMiddleOfEnteringANumber) {
self.userIsInTheMiddleOfEnteringANumber = NO;
}
[self.brain pushOperand:[self.display.text doubleValue]];
}
- (IBAction)clearPressed {
self.stackDisplay.text = #"";
[self.brain clearStack];
self.userIsInTheMiddleOfEnteringANumber = NO;
self.display.text = #"0";
}
#end
I got a maybe similar error, where some UIButtons had empty text, although by outputting titleLabel.text got the correct text value. I deleted the Buttons and added them identically to what it has before been in the storyboard. Then it worked.