UITextfield to NSUserDefaults type error - ios

I have a UITextField and I wish to extract the integer value from it and put it into a NSUserdefaults.
#property (weak, nonatomic) IBOutlet UITextField *defaultTipPercentage;
[defaults setInteger: defaultTipPercentage forKey:#"another_key_that_you_choose"];
I'm getting an error saying
Use of undeclared identifer 'defaultTipPercentage'. did you mean '_defaultTipPercentage?'
I tried this but I get an error
Incompatible pointer to integer conversion sending 'UITextField *_weak' to parameter of type 'NSInteger'(aka 'Int')
Pretty much just incompatible types. I was wondering what would be a quick fix for this

You have 2 problems.
You can't write a text field directly to user defaults - you need the text, or rather, the integer value of the text.
With a property, you either need to refer to it using self.defaultTipPercentage (which uses the getter), or _defaultTipPercentage, which refers to the backing instance variable directly. Using self.xxx syntax is generally safer.
Jenox already posted code to solve the first problem in the comments.
To also fix the second problem, you need to use property list syntax:
NSInteger tip = [self.defaultTipPercentage.text integerValue];
[defaults setInteger:tip forKey:#"another_key_that_you_choose"];

NSInteger tip = [self.defaultTipPercentage.text integerValue];
[defaults setInteger:tip forKey:#"another_key_that_you_choose"];

Related

Proper updating of a 32bit method to 64bit support

I have a method I am trying to update to 64-bit support for my app. I have lots of these warnings.
The issue is with the below example. I get the warning:
Implicit conversion loses integer precision NSInteger to int
- (int) aMethod {
NSUserDefaults *u = [NSUserDefaults standardUserDefaults];
return [u integerForKey:#"someKey"];
}
If I change the return type to NSInteger I get
Conflicting return type in implementation of aMethod int vs NSInteger aka long
-(NSInteger) aMethod {
NSUserDefaults *u = [NSUserDefaults standardUserDefaults];
return [u integerForKey:#"someKey"];
}
I have tried casting the return type
return (NSInteger)[u integerForKey:#"someKey"];
or
return (long)[u integerForKey:#"someKey"];
But I can't get the error to go away unless I cast it to (int)
return (int)[u integerForKey:#"someKey"];
I have read many SO questions but I can't seem to get a good answer.
What is the proper way of updating this method?
The method:
- (int) aMethod ...
returns a value of type int. The method may first declared, probably in a header (.h) file, and then defined in an implementation (.m) file.
The statement:
return [u integerForKey:#"someKey"];
returns the result of calling integerForKey:, which is a value of type NSInteger.
NSInteger is not a type defined by the (Objective-)C language, rather it is a type alias (typedef) defined in the frameworks intended to represent the "natural" integer size on the platform. It is an alias for int on 32-bit platforms and long on 64-bit.
So your compiler error is telling you that the (now) 64-bit value is being truncated to fit a 32-bit result. There is no single right way to fix this, it depends on what the use of the value associated with #someKey is:
If the value should now be 64-bit then change the return type of aMethod; both in its separate declaration, if it has one, and in its implementation; to NSInteger. You will also need to check that wherever the method is called that returning an NSInteger value is acceptable, and you may need to make follow-on changes to variable types etc. You also need to look at places where the value associated with the key is set.
If the value associated with the key may remain as 32-bit then you can use intForKey: instead of integerForKey and leave the return type as is. You should also change where the key is set to store an int
HTH
Correction
There is (no longer?) a convenience method intForKey: on NSUserDefaults. Alternatives include: integerForKey: and casting; objectForKey: to obtain an NSNumber reference and then intValue; etc.

Sharing an array of custom objects with Today Extension (widget) with NSUserDefaults

this is my first stack post so please be constructive when reviewing my posting technique!
Basically, my problem is that I have an array of custom objects that I need to share with a today extension. The objects represent tasks in a to-do list, and their properties are used to store info about each task (name, location, dueDate, thumbnail, etc). The objects are stored in an array which is used to populate my to-do list. All I want to do is pass this array to my widget so that I can populate a second tableview which will act as a condensed version of the first (for the widget view).
I should point out that my widget is properly set up, as in I have properly linked it and the containing app together in 'groups'. I have also successfully used NSUserDefaults to pass an array of NSStrings to the widget, however, when I try to pass the array of objects to the widget, it crashes and my log reads:
*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (Xitem)'
I understand that this crash is related to archiving the object (Xitem), which seems to be a necessary step towards saving custom objects in NSUserDefaults. However, I have tested saving/loading the array within the same class of the containing app, and that works fine! (code below)
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:self.Xitems];
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.AaronTest"];
[defaults setObject:encodedObject forKey:#"myArray"];
[defaults synchronize];
NSUserDefaults *defaults2 = [[NSUserDefaults alloc] initWithSuiteName:#"group.AaronTest"];
NSData *encodedObject2 = [defaults2 objectForKey:#"myArray"];
NSArray *array2 = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject2];
for (Xitem *t in array2){
NSLog(#"*****%#*****", t.itemName);
}
Okay so as explained, the above code works as expected. However, when i insert the second 'unarchiver' half of this code into my today widget, i get the aforementioned error. Below is my code to show how I encode/decode the object (it may be worth noting that this object was created for the simplicity of my debugging and only contains a NSString property):
Xitem.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface Xitem : NSObject <NSCoding>
{
NSString *itemName;
}
-(void)encodeWithCoder:(NSCoder*)encoder;
-(id)initWithCoder:(NSCoder*)decoder;
#property NSString *itemName;
#end
Xitem.m
#import "Xitem.h"
#implementation Xitem
#synthesize itemName;
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.itemName forKey:#"iName"];
}
-(id)initWithCoder:(NSCoder*)decoder
{
self = [super init];
self.itemName = [decoder decodeObjectForKey:#"iName"];
return self;
}
#end
I could also post my widget and containing app code, but it doesn't differ from the first set of code i posted (apart from the renamed variables such as 'defaults2'). I should point out that I really have exhausted resources while trying to solve this problem, but the fact that using NSKeyedArchiver solely in the containing app works, has left me stumped.
I realise that this post is very similar to my own problem, but the author decides to opt for a workaround, whereas I would actually like to know why this doesn't work. I'm a new developer and I'm doing my best to pickup on the best working practices so any advice would be greatly appreciated.
I think it's also possible to replace my object (class) with an NSDictionary? However I would like to avoid this if possible because it would cause many conflicts in the main app, but obviously if that is the correct method I will tackle that problem. On a side note, if a dictionary would be better than an object for my requirements (to-do list with properties of UIImage, CLLocation, etc) for any other reasons (memory or accessibility for example) please do elaborate and help me to understand why!
Many thanks for anyones time :)
Okay so I just fixed this. Incase anyone has the same problem, go to: 'Targets' > 'Widget' > 'Build Phases' > 'Compile Sources' > add custom class there (Xitem.m)

Dynamical value in define var_name block

In my app i have such thing
#define ACCT_ID #"someaddress#gmail.com"
Is there any way to set dynamical value to this define block?
FOr ex. i make request to webserver, which returns me some string, and later i set this string into #define block.
Is there anyway to achieve this?
you also use nsuserdefault like:
set value
[[NSUserDefaults standardUserDefaults]setObject:#"abc#gmail.com" forKey:#"ACCT_ID"];
get value
NSString *str= [[NSUserDefaults standardUserDefaults]valueForKey:#"ACCT_ID"];
remove value
[[NSUserDefaults standardUserDefaults]removeObjectForKey:#"ACCT_ID"]
Well of course not, since all lines begin with # happening during pre-processor compilation.
Therefor, the value given to ACCT_ID detemind before even your program compiled and it can not be changed
Ended up with following:
#define ACCT_ID [[SingletonClass myinstance] getEmail]

Using output parameters with ARC

So I have read this question, which seems to be exactly the kind of problem I am having, but the answer in that post does not solve my problem. I am attempting to write a data serialization subclass of NSMutableData. The problematic function header looks like this:
-(void)readString:(__autoreleasing NSString **)str
I do some data manipulation in the function to get the particular bytes the correspond to the next string in the data stream, and then I call this line:
*str = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
No errors in this code. But when I try to call the function like so:
+(id) deserialize:(SerializableData *)data
{
Program *newProgram = [[Program alloc] init];
[data readString:&(newProgram->programName)];
On the line where I actually call the function, I get the following error:
Passing address of non-local object to __autoreleasing parameter for write-back
I have tried placing the __autoreleasing in front of the NSString declaration, in front of the first *, and between the two *'s, but all configurations generate the error.
Did I just miss something when reading the other question, or has something in the ARC compiler changed since the time of that post?
EDIT:
It seems that the problem is coming from the way I am trying to access the string. I can work around it by doing something like this:
NSString* temp;
[data readString&(temp)];
newProgram.programName = temp;
but I would rather have direct access to the ivar
You can't. You might gain insight from LLVM's document Automatic Reference Counting, specifically section 4.3.4. "Passing to an out parameter by writeback". However, there really isn't that much extra detail other than you can't do that (specifically, this isn't listed in the "legal forms"), which you've already figured out. Though maybe you'll find the rationale interesting.

UIProgressView value from plist inside UITableViewCell

I'm trying to pass a number from a plist to a UIProgressView inside a UITableViewCell. So far, I have done this:
myUIProgressView.progress =[[myArray objectAtIndex:indexValue] valueForKey:#"myUIProgressViewValue"];
However, when doing this I get an error: Assigning to 'float' from incompatible type 'id'
How can I fix this?
Also, the value coming from the plist is not a decimal (because the number is used more than once), but instead a whole number. I need to somehow add a . before the number within that piece of code above, but I am not sure how to go about that.
Try this:
myUIProgressView.progress = [[[myArray objectAtIndex:indexValue] valueForKey:#"myUIProgressViewValue"] floatValue] / 10;
Try This
myUIProgressView.progress =[[[myArray objectAtIndex:indexValue] floatValue]valueForKey:#"myUIProgressViewValue"];

Resources