NSString format issue - {( String )} - ios

I am fetching data from core data and trying to print the name of the object at valueForKey. This has never caused me any trouble however when getting a direct object but the object I am getting is from an NSSet relationship.
When I print out the value I want, it displays in this format.
{(
Bob Marley
)}
{(
Jack Daniels
)}
etc...
I have used NSString stringWithFormat, I have tried componentsSeperatedByString, however neither of these work. If another question has been asked, I cannot find it on here. The issue is identical in a UILabel as well. Makes no difference where I print it.
Hopefully it's a simple issue.
My code for getting the value is.
//Company * company
//Employee is related in a many-many relationship
NSString * name = (NSString *)[self.company.contractor valueForKey:#"contractorName"];
NSLog(#"Name: %#", name);
Thanks.

self.company.contractor is NSArray.
So you need to do
NSString * name = (NSString *)[[[self.company.contractor allObjects] firstObject] valueForKey:#"contractorName"];
Also refer to my previous answer

Related

-[Person componentsSeparatedByString:]: unrecognized selector sent to instance

I'm new to programming, and I feel a little intimidated posting, and I'm stuck. I don't want a quick fix! Please help me understand this.
I've created a custom method with a name, age, height and gender. It gets called when the NSMutableArray adds custom objects to the array. For some reason I cannot pull said items out of the NSMutableArray. Let's say the age needs to be printed out. I get a error saying...
-[Person componentsSeparatedByString:]: unrecognized selector sent to instance
Person.m
- (id)initWithName:(NSString *)n
age:(int)a
height:(float)h
gender:(char)g
{
self = [super init];
if (self) {
self.name = n;
self.age = a;
self.height = h;
self.gender = g;
}
return self;
}
- (NSString *)description
{
NSString *descriptionString = [[NSString alloc] initWithFormat:#"%#, %d, %.1f, %c",
self.name,
self.age,
self.height,
self.gender];
NSLog(#"Description String: %#", descriptionString);
return descriptionString;
}
When adding objects to the NSMutableArray they get converted to a NSString? How do I get the peoples age without the whole strings name and height in the NSLog?
ViewController.m
[self.people addObject:[[Person alloc] initWithName:#"Jake" age:29 height:73.5 gender:'f']];
[self.people addObject:[[Person alloc] initWithName:#"Jerry" age:24 height:82.3 gender:'m']];
[self.people addObject:[[Person alloc] initWithName:#"Jessica" age:29 height:67.2 gender:'f']];
NSString *mystring1 = [self.people objectAtIndex:0];
NSLog(#"%#", mystring1);
// Works
//NSString *list = #"Norm, 42, 73.2, m";
NSArray *listItems = [self.people[0] componentsSeparatedByString:#", "];
NSLog(#"List Items: %#", listItems[1]);// age
Output
Description String: Jake, 29, 73.5, f
Jake, 29, 73.5, f
-[Person componentsSeparatedByString:]: unrecognized selector sent to instance
Solved:
Notice the extra [ age];
int age = [[self.people objectAtIndex:0]age];
NSLog(#"%d", age);
I think the reason it seems like your object is getting converted to a string is this line,
NSString *mystring1 = [self.people objectAtIndex:0];
You need to specify the property if that is all you want to print
NSString *nameString = [[self.people objectAtIndex:0]name];
You can't perform componentsSeparatedByString on your Person object since it's not a string and doesn't have that method. (NSMutableArray objects are not automatically converted to NSStrings.) But to get the age of your Person, should be fairly simple anyway. Just access Person's age property:
int age = self.people[0].age;
NSLog(#"Age: %d", age);
Edit: You can technically use componentsSeparatedByString on your mystring1 NSString, like so:
NSArray *listItems = [mystring1 componentsSeparatedByString:#", "];
NSLog(#"List Items: %#", listItems[1]);// age
But again, I don't see the point of doing this when you can access the Person's age property directly.
The componentsSeparatedByString method is an instance method of NSString class. You can't call it on your Person class in this way.
I don't know why you need that code, if you are trying to access age, then:
NSLog(#"Age %d", self.people[0].age);
is enough. If you are trying to achieve any other thing, then you can get the components like:
NSArray *listItems = [self.people[0].description componentsSeparatedByString:#", "];
NSLog(#"List Items: %#", listItems[1]);// age
One would think this would work; however, I can not call .age on my array.
NSLog(#"Age %d", self.people[0].age);
Gives the following output...
Property 'age' not found on object of type 'id'
One would also think componentsSeparatedByString would work. It doesn't split my string by the comma and gives an error.
-[Person componentsSeparatedByString:]: unrecognized selector sent to instance
Solved READ UP
I think you are getting confused about why when you log the object you are getting a string, but you can't perform any methods on it.
And here is why you think you are getting a string, you've implemented the description property, which comes from the NSObject protocol. When you do a log of an object with a %# parameter you are getting the result of this property, which is a string.
So looking at your code:
NSString *mystring1 = [self.people objectAtIndex:0]; //1
NSLog(#"%#", mystring1); //2
The first thing is that you are getting the first object out of your array. objectAtIndex returns an id, which is a pointer to an NSObject. It is not a strongly typed return. You are allocating it to an NSString which is wrong, because it as actually a person object. But since you aren't calling any NSString methods on it, the compiler is not flagging this incorrect assignment.
The second thing is that you are just getting the result of the description property, as I've already mentioned.
Your edited solution:
int age = [[self.people objectAtIndex:0]age];
Works, but here is why: you are getting the objectAtIndex:0 which returns an id. Then you are sending it the message age. Objective-C is a dynamic language, which means you can send any message to any object (although you get a run-time crash if the object does not implement the method) In this case, your Person object does implement an age method (since it's a public property) so you get an age back.
A different way of doing it:
NSInteger age;
Person *person = self.people.firstObject;
if (person) {
age = person.age;
} else {
age = NSNotFound;
}
Why am I doing it this way?
Firstly, I am getting the firstObject out of the array and putting it into a typed variable. This is safer, as if there is no object at index 0 (i.e. the array is empty) then you won't crash your app. firstObject returns the first object if it exists, on a nil if it doesn't.
Secondly, Only if the person has been correctly extracted from the array, do I assign the age to an NSInteger variable. You should prefer the specific types of NSInteger over int (and CGFloat over float) because they will use the correctly sized variable when running on 32-bit or 64-bit` systems.
Thirdly, if person cannot be created I am assigned the value of NSNotFound to the age. This is a typedef for a very large number, one that you can compare against. Just returning 0 in age is not enough to tell you there was an error. The person could have an age of 0. with this code you can test the age with:
if (age != NSNotFound) {
// This is a valid age, do something with it
} else {
// A person object could not be extracted from the array, this is not a valid age
}
Is this overkill? Not really. When you start writing real, complex apps, this sort of defensive programming will come naturally to you. Arrays can be empty, your data could be incorrectly created, etc. Writing code that gracefully handles these eventualities is the real skill of programming. Unfortunately, It's a bit more long winded, and most tutorials that you find on the web show you the simple, happy path.
I hope this gives you a better idea of what your code is doing and what more you could be doing to write robust code.

Why is Parse PFObject response borked?

I am starting a new project on Parse.
I am trying to retrieve my own properties on a custom class PFObject being returned from a query. I'm using [object objectForKey:#"key"] and it isn't working. I logged the description of the object I was getting back from the query and it's format is:
<Horse: 0x7f93e9c7e240, objectId: gLqeyEfOr6, localId: (null)> {
hidden = 0;
visibleName = "Horsey";
}
Notice that "hidden" and "visibleName" have been encapsulated by { }'s . This seems to be my issue. Why is this format happening to my custom properties? How do I get the data for keys "hidden" and "visibleName" out of my PFObject?
Thanks
You can access a PFObject directly as a dictionary - the {} is just added by the description method (which is the method that gets invoked when you NSLog the object as a string) to indicate a dictionary. What you have should work. You can also use the more compact notation -
NSString *visibleName=myPFObject[#"visibleName"];
NSNumber *hidden=myPFObject[#"hidden"];
What results are you getting when you say "it doesn't work"?

Find object by name in NSMutableArray

I have a generic person object with properties personName, lastName, and age. I am storing the user input into an NSMutableArray and I wanted to find a under by his/her name in the array. I have tried finding a bunch of different solutions but none that quite really work.
This is my main.m
#autoreleasepool {
char answer;
char locatePerson[40];
//Create mutable array to add users for retrieval later
NSMutableArray *people = [[NSMutableArray alloc] init];
do{
Person *newPerson = [[Person alloc]init];
[newPerson enterInfo];
[newPerson printInfo];
[people addObject:newPerson];
NSLog(#"Would you like to enter another name?");
scanf("\n%c", &answer);
}while (answer == 'y');
NSLog(#"Are you looking for a specific person?");
scanf("%c", locatePerson);
//This is where I need help
int idx = [people indexOfObject:]
}
This is very basic but I am new to objective-c and I wanted to try and find the user by name. The solutions I've seen have used the indexesOfObjectsPassingTest method. But I was wondering if I can't just use the indexOfObjectmethod the way I did there to locate a person by its name?
Any help is appreciated.
This is one of those hard problems you should avoid with some up-front design. If you know that you are putting things into a collection class and will need to get them out again based on some attribute (rather than by order of insertion) a dictionary is the most efficient collection class.
You can use a NSDictionary keyed with Person's name attribute. You can still iterate over all the objects but you will avoid having to search the whole collection. It can take a surprisingly long time to find a matching attribute in a NSArray! You wouldn't even have to change your Person object, just do
NSDictionary *peopleDictionary = #{ person1.name : person1, person2.name : person2 };
or add them one by one as they are created into a NSMutableArray.
You can try something like this assuming that 'name' is a property for your Person class.
NSUInteger i = 0;
for(Person *person in people) {
if([person.name isEqualToString:locatePerson]) {
break;
}
i++;
}

Integer from .plist

I'm new to plists, and I really need to use one. What I have is a plist where different numbers are stored, under two dictionaries. I need to get that number which is stored, and make it an integer. This process will be run from a method called 'readPlist.
The plist is called 'properties.plist'. The first dictionary is called 'Enemies'. It contains various other dictionaries, which will have the name stored in the NSMutableString called 'SpriteType'. The name of the number will have the format 'L - %d', with the %d being an integer called 'LevelNumber'.
If possible, can someone give me the code on how to get that integer using the information, and the names of dictionaries above.
I have looked around at how to access plists, but the code that people have shown doesn't work.
Thanks in advance.
EDIT: Too make it more understandable, this is my plist. What i want in an integer, called 'SpriteNumber' to be equal to the value of 'L - %d'
If you read the contents of your plist into a dictionary (I won't tell you how to do it, but this is the tutorial I refer to often), then it's a matter of getting the string out of the key for the level with [[myDictionary objectForKey:#"key"]stringValue];. Then, using of NSString's extremely helpful -stringByReplacingOccurencesOfString:withString: to get rid of the "L -" part and only get a numerical value. Finally, get an integer from the string with [myString intValue].
well, the easiest way would be something like :
-(int) getMosquitoCountForLevel:(int) level {
int mosquitoCount=0;
NSString *gsFile = #"whateverFullyQualifiedFileNameYourPlistIs";
NSDictionary* definitions = [NSDictionary dictionaryWithContentsOfFile:gsFile];
NSDictionary* mosquitos = [definitions objectForKey:#"Mosquito"];
if(mosquitos) {
NSString *levelKey = [NSString stringWithFormat:#"L - %d",level];
NSNumber *mosquitoCountAsNumber = [mosquitos objectForKey:levelKey];
if(mosquitoCountAsNumber) {
mosquitoCount=[mosquitoCountAsNumber intValue];
} else {
CCLOGERROR(#"%# - Mosquito definitions in %# does not contain a en entry for level %#.",self.class,gsFile,levelKey);
}
} else {
CCLOGERROR(#"%# - file %# does not contain a Mosquito dictionary.",self.class,gsFile);
}
return mosquitoCount;
}
this compiles but not tested with actual data.

setObject:forKey: of NSMutableDictionary overwrites all data in dictionary

for ( int cnt = 0 ; cnt < nPeople ; cnt++ )
{
ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, cnt);
NSString *firstName = (NSString *)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
NSString *lastName = (NSString *)ABRecordCopyValue(ref, kABPersonLastNameProperty);
NSString *fullName;
/* skipped code at here : code to merge firstName and lastName to fullName. In my country, many of us don't separate first name and last name */
// tempKeyString : NSString variable that has key of fullNameArray value for nameDictionary.
// fullNameArray : to keep some fullName variables for tempKeyString.
if (!tempKeyString) // there's no tempKeyString, a.k.a. it's the first fullName.
{
// it's not important to know about GetUTF8String:fullName. It's for my own language.
tempKeyString = [self GetUTF8String:fullName];
[fullNameArray addObject:fullName];
}
else
{
if ([tempKeyString characterAtIndex:0] == [[self GetUTF8String:fullName] characterAtIndex:0]) // if fullName has the same tempKey with fullNameArray.
{
[fullNameArray addObject:fullName];
}
else // if fullName has different tempKey with fullNameArray.
{
//tempKey : key data for fullNameArray
NSString *tempKey = [tempKeyString substringToIndex:1];
// tempDict : to keep the deep copy of nameDictionary before adding new key.
NSDictionary *tempDict = [nameDictionary mutableDeepCopy];
// add new key (tempKey) with new value (fullNameArray)
// PROBLEM : ALL values (including previous values) in dictionary(nameDictionary) are overwritten to a new value(fullNameArray).
[nameDictionary setObject:fullNameArray forKey:tempKey];
//empties fullNameArray so that it can get the new fullName of the new tempKey.
[fullNameArray removeAllObjects];
//refresh tempKeyString, and add the new fullName.
tempKeyString = [self GetUTF8String:fullName];
[fullNameArray addObject:fullName];
...
}
}
}
I'm trying to make a NSMutableDictionary object from the contacts of my iPhone. Why I make a NSMutableDictionary typed object is that I need indexes for contacts, and it doesn't look easy to make indexes from ABAddressRef typed object directly. I also need to make searching function..
There was no problem when I just coded, but after debugging the only problem makes me crazy. After I apply the array named fullNameArray with the key named tempKey to the namedDictionary, I can find the nameDictionary has all values with them of fullNameArray. All previous data were overwritten! I tried to make a deep copied version of previous nameDictionary before applying fullNameArray and copy it to the newer nameDictionary. However, when I checked the breakpoint at the third line, I can't find the previous data at the tempDict.
I added more codes and comments. It might help more than my explanation.. any questions are pleased!
I tried to find the reason from here - StackOverflow -, and other webpages all the night, but I couldn't find any similar problems.. please help me! Thank you so much in advance!!
The reason why it get emptied is because
[nameDictionary setObject:fullNameArray forKey:tempKey];
here, you set up your dictionary with the object "fullNameArray", then
[fullNameArray removeAllObjects];
remove all the values inside this array, effectively, removing your object in the "nameDictionary", they are the same object, it's not a deep copy of fullNameArray that you store inside your dictionary. Why did you need to store anything into your array anyway? You're only storing 1 value.
[nameDictionary setObject:fullName forKey:tempKey];
will do what you need. Sorry if I mistaken your question, it's quite hard to understand

Resources