NSCoding - reuse object for writing? - iphone

I have a Singleton which has an NSMutableArray containing a Class, the Class contains the proper NSCoding routines to encode/decode the data - it all works fine.
However I'd now like to also save data that is not part of the Class (array), but instead is part of the Singleton and is not specific to each item in the Class/array. So I've added the appropriate code in the Singleton including:
BOOL alarmIsOn;
...
#property(nonatomic,assign) BOOL alarmIsOn;
...
#synthesize alarmIsOn;
...
[encoder encodeBool:alarmIsOn forKey:#"alarmison"];
...
alarmIsOn=[decoder decodeBoolForKey:#"alarmison"];
When I save my data I previously used this which works perfectly:
GlobalData *globDat=[GlobalData getSingleton];
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:globDat.allMsgs];
[encodedObject writeToFile:plistPath atomically:YES];
Now I'd like to add the following to include the additional data from the Singleton:
encodedObject = [NSKeyedArchiver archivedDataWithRootObject:globDat.alarmIsOn];
[encodedObject writeToFile:plistPath atomically:YES];
However it gives me this error in Xcode:
Automatic Reference Counting Issue: Implicit conversion of 'BOOL' (aka 'signed char') to 'id' is disallowed with ARC
And this warning:
Semantic Issue: Incompatible integer to pointer conversion sending 'BOOL' (aka 'signed char') to parameter of type 'id'
What am I doing wrong, and how can I fix this?

Your error is that
globDat.alarmIsOn
is a bool and
NSKeyedArchiver archivedDataWithRootObject:
wants an
id
which is another word for an opaque pointer to an object. A bool is just a byte. How exactly you want to fix it is up to you. To use that routine requires an object.

Related

Return type from valueForKeyPath:?

This is probably pilot error on my part, but I am a little confused why this does not return an int (as thats the type of the property identified by the key path). Does valueForKeyPath: return an object instead, can anyone explain.
// Simple Object
#interface Hopper : NSObject
#property(nonatomic, assign) int mass;
#end
// Test
Hopper *hopper = [[Hopper alloc] init];
[hopper setMass:67];
NSLog(#"HOPPER: %d", [hopper valueForKeyPath:#"mass"]);
.
WARNING: Conversion specifies type 'int' but the argument has type 'id'
Yes, it returns an objc object:
- (id)valueForKeyPath:(NSString *)keyPath;
Details for automatic conversions from non-objc objects to objc objects (e.g. NSNumber and NSValue) is covered in Accessor Search Patterns for Simple Attributes.
Therefore, you would use the objc object format specifier %#:
NSLog(#"HOPPER: %#", [hopper valueForKeyPath:#"mass"]);
valueForKeyPath returns an object. int and char types are not objects. Access the property via the . operator or similar.
NSLog(#"HOPPER: %d", [hopper mass]);
NSLog(#"HOPPER: %d", hopper.mass);
Edit: Didn't fully read example code, updated answer

XCODE incompatible pointer type error

I am getting a casting error. My app is reading a text file from a webpage using 'stringWithContentsOfURL' method. I want to parse the individual lines into separate components. This is a snippet of the code.
int parameterFive_1 = 0;
parameterFive_1_range = NSMakeRange(0,10)
lines = [response componentsSeparatedByString:#"\r"];
parameterFive_1 = CFStringGetIntValue([[lines objectAtIndex:i] substringWithRange:parameterFive_1_range]);
I am getting the following error message:
" Implicit conversion of an Objective-C pointer to 'CFStringRef' (aka 'const struct __CFString *') is disallowed with ARC"
I thought it might be the compiler option but changing it to the default is not making a difference. Can anyone provide any insight?
Just cast the NSString* to CFStringRef to satisfy ARC:
parameterFive_1 = CFStringGetIntValue((__bridge CFStringRef)[[lines objectAtIndex:i] substringWithRange:parameterFive_1_range]);
The __bridge keyword here lets ARC know that it doesn't need to transfer ownership of the string.

Use of asterisk in variable names

The book "iPhone Programming. The Big Nerd Ranch Guide" cites the following method (page 96)
(void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *) views {
MKAnnotationView *annotationView = [views objectAtIndex:0];
id <MKAnnotation> mp = [annotationView annotation];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate], 250, 250);
[mv setRegion:region animated:YES];
}
I'm confused because of the asterisk usage. The line that begins with "MKAnnotationView" and the following one can be represented in an abstract fashion by:
ObjectType variableName = [object message];
Questions:
In the first case an asterisk precedes the variable name, but not in the second. Why?
In the case where the asterisk is used, should not be the pointer the assigned to nil?
Thanks.
I tend to think of it as what variable types require an asterisk, not what variable names require an asterisk. Objective C doesn't allow you to allocate objects on the stack like so:
// Declare an NSObject. Won't work.
NSObject myObject;
Instead, all objects must be dynamically allocated on the heap using pointers like so:
// Declare a pointer to an NSObject. Will work.
NSObject* myObject = [[NSObject alloc] init];
id is a special Objective C keyword that just means "A pointer to some Objective C object". This may or may not inherit from NSObject and is dynamically typed. What's important to note is that, while there is no asterisk, this is still a pointer to an object:
// Same as before. Will work.
id myObject = [[NSObject alloc] init];
The only difference is that the compiler has no information about what myObject is.
As a finishing note, id <MKAnnotation> is exactly the same as a regular id, but with some extra information for the compiler. Read it as "a pointer to some Objective C object that behaves like an MKAnnotation". MKAnnotation, in this case, is the name of a Protocol whose required methods you are declaring that particular id to implement.
id is already defined as a pointer to a struct. If you look at its definition in objc.h, you would that id is defined as,
typedef struct objc_object {
Class isa;
} *id;
Since it is already a pointer to an objc_object, you can create pointers to objects without using the asterisk as,
id myObject;
Also saying that an object is type id gives the compiler absolutely no information about the object except its class which comes from the isa property.
An NSObject on the other hand is defined as,
#interface NSObject <NSObject> {
Class isa;
}
To create a pointer to an object of NSObject or one of its subclass (such as MKAnnotationView), you would declare it as,
NSObject *myObject;
MKAnnotationView *myObject;
We are putting the asterisk here to denote that it is a pointer.
Specifying the protocol(s) next to the type gives the compiler more information for static-type checking.
You should check out this article for a brief introduction to the differences between id and NSObject. For an in-depth understanding, checkout this article on the Objective-C runtime.
ObjectType is normally something like "pointer to a MKAnnotationView", which is represented in Objective-C as it is in C: "MKAnnotationView *". Exceptions include the "id" type, various integer and floating point types (including their typedefs), enums (which are really integer types), and some small structs like CGRect.

iphone program warnings

I have some code added in viewWillAppear;
curr_rep_date = [tmpRptDt
stringByReplacingOccurrencesOfString:[NSString
stringWithFormat:#"%d",tmpYrVal]
withString:[NSString
stringWithFormat:#"%d",(tmpCurrYearInt-2)]];
When I build, I get the following warning;
warning: incompatible Objective-C types assigning 'struct NSArray *', expected 'struct NSMutableArray * }
Also
warning: assignment makes pointer from integer without a cast for:
replist_rptdt_dict =
PerformXMLXPathQuery(xmlData,
#"//XX/Period[#XX]");
Please let me know the reason.
Thanks.
replist_rptdt_dict = PerformXMLXPathQuery(xmlData, #"//XX/Period[#XX]");
First, the Objective-C standard is to use camel cased english names for variables. replist_rptdt_dict is confusing (it almost sounds like you have a list dictionary something what huh?).
warning: incompatible Objective-C
types assigning 'struct NSArray *',
expected 'struct NSMutableArray *' }
This will happen if you have:
- (NSArray *) foo;
...
{
NSMutableArray *bar = [someObject foo];
}
That is, bar is a more specific type -- a subclass -- than foo's return value. The compiler is complaining because your code is quite likely going to crash if you send, say, removeObjectAtIndex: to what is quite likely an immutable array.

Pass and access structures using objective-c

I want to know how to pass structures to another function and subsequently access that structure in the called function. I'm developing for the iPhone and the reason I'm using structs is so that I can eventually pass data as structs to a server being built in C.
Here's the structure:
struct userInfo{
NSString *firstName;
NSString *lastName;
NSString *username;
NSString *email;
NSString *ipAddress;
double latitude;
double longitude;
};
Here I'm simply fetching some user inputed data along with some CoreLocation data and the iPhone's IP Address:
- (IBAction)joinButton {
struct userInfo localUser;
localUser.firstName = firstName.text;
localUser.lastName = lastName.text;
localUser.username = username.text;
localUser.email = emailAddress.text;
localUser.ipAddress = localIPAddress.text;
localUser.latitude = currentLocation.coordinate.latitude;
localUser.longitude = currentLocation.coordinate.longitude;
[myNetworkConnection registerWithServer:&localUser];
}
function handling the struct:
- (void)registerWithServer:(struct userInfo*)myUser {
printf("First name is: %s", myUser.firstName);//error when compiling
}
the complier throws this error: request for member 'firstName' in something not a structure or union. Is that struct out of scope when I try to access it in the second function?
You are passing in a pointer to a struct. Use the -> operator, not the dot.
myUser->firstName
I can't help but think you should really make that a proper objective-C object with properties - more work but then it'll all behave better and live within the NSObject ecosystem.