Pass and access structures using objective-c - iphone

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.

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

NSCoding - reuse object for writing?

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.

How to return a array list of non-object type in Objective-C

I have a method which should return a list of non-object types. Specifically a list of CLLocationCoordinate2D. I would like to have it as a list and not as an NSArray I use the outcome to create a MKPolyLine using
+ (MKPolyline *)polylineWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count
With the code below I get an "Array initializer must be an initializer" list.
-(CLLocationCoordinate2D[])pathBetween:(CLLocationCoordinate2D)start and:(CLLocationCoordinate2D)end withNumberofPoints:(int)nrOfPoints{
CLLocationCoordinate2D returnPath[nrOfPoints];
for (int i=0; 1<nrOfPoints; i++) {
float fraction=i/(nrOfPoints);
CLLocationCoordinate2D coord=[self coordinateAtFraction:fraction between:start andEnd:end forAccuracy:.02];
returnPath[i]=coord;
}
return returnPath;
}
If I initialize the list using
CLLocationCoordinate2D returnPath[nrOfPoints]={};
I get "Variable sized object may not be initialized".
If I remove the [] from the method I get "returning 'CLClocationCoordinate2D[nrOfPoints]' from a function with incompatible result type 'CLLocationCoordinate2D'"
Any Ideas?
You are trying to create the array on the stack and then return it. That won't work.
There are several things you can do here:
malloc the array of points.
returnPath = malloc(sizeof(CLLocationCoordinate2D) * nrOfPoints;
This would mean the caller would have to free the returned pointer.
return the array in an NSData
NSMutableData* returnData = [[NSMutableData alloc] initWithLength: sizeof(CLLocationCoordinate2D) * nrOfPoints];
returnPath = [returnData mutableBytes];
// the other stuff
return [returnData autorelease];
This means that you don't have to worry about memory management any more than for any other Objective-C object.
Have the caller supply the array e.g.
-(void) getPath: (CLLocationCoordinate2D*) returnPath // caller allocates a big enough buffer
between: (CLLocationCoordinate2D)start
and: (CLLocationCoordinate2D)end
withNumberofPoints:(int)nrOfPoints
{
// code as question but no allocation or return value
}
CLLocationCoordinate2D returnPath[nrOfPoints]; value for noOfPoints should be available at complile time. if u replace line with CLLocationCoordinate2D *returnPath = (CLLocationCoordinate2D *) malloc(nrOfPoints * sizeof (CLLocationCoordinate2D));
array would be available at run time. But I am not sure sizeof method will return the object size.
As pointed out by Kevin in the comment: you have to do something about the fact that your return argument is a local variable. The reference "returnPath" will point into Nirvana outside your function. Here is a video that explains what happens there, enjoy: http://www.youtube.com/watch?v=6pmWojisM_E
For the array of CLLocationCoordinate2D, look at this post here:
NSMutableArray of ClLocationCoordinate2D
Hope this helps.

How can I see values of Object in NSLog?

Suppose I have an object containing some data.
How can I see that data using NSLog?
If anyone is not clear about my question, then can ask me again.
If you want to see an NSArray and NSDictionary and etc objects then you can directly print like NSLog(#"%#",object);
If it is an user defined object then you need to display by calling with property (attribute).
User defined object with name object and properties like
NSString *property1;
int property2;
NSMutableArray *property3;
Print them in the console as follows:
NSLog(#"%#, %d, %#" object.property1,object.property2,object.property3);
If you implement the -(NSString*)description method in your class then you can use NSLog to output a summary of the data. Of course, you can also directly output any property.
For example:
NSLog (#"%# %d", object, object.integer);
The first part calls the description method and outputs that; the second part gets the value of the integer property of object and outputs that.
Every Objective-c Object (this comes from NSObject) has a property called description. So if you want to print information about your class this is the way to go.
#implementation MyClass
- (NSString*)description
{
return [NSString stringWithFormat:#"MyClass:%#", #"This is my class"];
}
so if you do a call like this.
MyClass *myClass = [[MyClass alloc] init];
NSLog(#"%#", myClass);
NSLog(#"%#", [myClass description]); //Same as the line above
Then it will write "MyClass:This is my class" to the console (in this case it will print it twice).
Implement description of the given class.
-(NSString*)description {
return [NSString
stringWithFormat:#"<%#> name: `%#` size: `%#`",
NSStringFromClass(self), self.name,
NSStringFromCGSize(self.size)];
}
NSLog(#"%#", object); // <Object> name: `Harry` size: `{2, 2}`
extension Object: CustomStringConvertible {
var description: String {
"<\(Self.self)> name: `\(name)` size: `\(size)`"
}
}
print(object) // <Object> name: `Harry` size: `(2.0, 2.0)`
I would suggest these:
Objects:
For objects like Dictionary, Array, Strings do it like:
NSLog(#"%#", object);
For basic data-types like integers
NSLog(#"%i",intVal);
For type encoding you should see http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
Use this class https://github.com/arundevma/ICHObjectPrinter
NSLog(#"Object description is %#",[ICHObjectPrinter descriptionForObject:person]);
NSLog(#"My object data:%#",[myObj someData]);
NSLog(#"My object Other data:%#",[myObj someOtherData]);
Or directly:
NSLog(#"%#",myObj);
NSLog(#"Description:%#",[myObj description]);
Additionally to Satya's answer, if you want to see basic c data types, use the format specifiers. Such as %d for an integer:
NSLog (#"My integer:%d", myObject.myInteger);
The complete list is here:
http://www.cplusplus.com/reference/clibrary/cstdio/printf/

Static string variable in Objective C on iphone

How to create & access static string in iPhone (objective c)?
I declare static NSString *str = #"OldValue" in class A.
If i assign some value to this in class B as str = #"NewValue".
This value persists for all methods in class B. But if I access it in class C (after assignment in B) I am getting it as OldValue.
Am I missing something? Should i use extern in other classes?
Thanks & Regards,
Yogini
Update: As of Xcode 8, Objective-C does have class properties. Note, it's mostly syntactic sugar; these properties are not auto-synthesized, so the implementation is basically unchanged from before.
// MyClass.h
#interface MyClass : NSObject
#property( class, copy ) NSString* str;
#end
// MyClass.m
#import "MyClass.h"
#implementation MyClass
static NSString* str;
+ (NSString*) str
{
return str;
}
+ (void) setStr:(NSString*)newStr
{
if( str != newStr ) {
str = [newStr copy];
}
}
#end
// Client code
MyClass.str = #"Some String";
NSLog( #"%#", MyClass.str ); // "Some String"
See WWDC 2016 What's New in LLVM. The class property part starts at around the 5 minute mark.
Original Answer:
Objective-C doesn't have class variables, which is what I think you're looking for. You can kinda fake it with static variables, as you're doing.
I would recommend putting the static NSString in the implementation file of your class, and provide class methods to access/mutate it. Something like this:
// MyClass.h
#interface MyClass : NSObject {
}
+ (NSString*)str;
+ (void)setStr:(NSString*)newStr;
#end
// MyClass.m
#import "MyClass.h"
static NSString* str;
#implementation MyClass
+ (NSString*)str {
return str;
}
+ (void)setStr:(NSString*)newStr {
if (str != newStr) {
[str release];
str = [newStr copy];
}
}
#end
Unlike Java, where a static variable is scoped for all instances of a class, static in C means that a variable is accessible only from within the file where it is declared. It allows you to do things like declare a static variable inside a function, which sets the value only the first time through, like this.
One thing you haven't mentioned is the relationship between classes A, B, and C. If they are in an inheritance hierarchy, and you're expecting the static variable to be inherited as in Java, the method described by zpasternack will work.
If the three classes are unrelated, and you just want to access the value declared in A, then extern is a more appropriate way to go. In this case, you want to declare the variable as extern in ClassA.h, then define it in Class.m. As long as ClassB and ClassC import ClassA.h, they will be able to link against the same extern definition.
One fine point is that, instead of using extern by itself, it's more robust to use OBJC_EXPORT, which is defined in objc-api.h and handles compiling under C++ as well. Here's a code sample:
// ClassA.h
OBJC_EXPORT NSString* commonString;
...
// ClassA.m
NSString* commonString = #"OldValue";
// ClassB.m
#import "ClassA.h"
...
commonString = #"NewValue"; // Can be inside a function or method
Of course, using externed variables in this way creates an infamous, much-maligned global variable, which is fragile in that anyone can read or write it, and access is uncontrolled. This is the simple approach, and answers your question about using static vs. extern. However, as a design principle, the encapsulation provided by wrapping the variable with class methods is much safer, albeit more complex. In object-oriented languages, when the effect you're trying to achieve is that of a class-static method, encapsulation is probably the right way to go.