Declare as NSString but Xcode treat as NSdata & received incompatible passing - iphone

I'm trying to pass an NSString address object to a UILabel text, but I received a warning from XCode compiler about incompatible pointer, as shown in the screen shot below:
And from the screen shot below you can see that my address object is declared as a NSString.
I had try displaying my NSString with:
NSLog(#"%#",[[LocationData objectAtIndex:rowDisplay] address]);
and it works without any incompatible pointer error. Can anyone please help? I have done some researching but I still can't find any solution.
My address is an object which gets stored into an NSArray. The address format is the always the same, for example "542 W 112 St New York NY 10025".
Thanks.

This might be due to the fact that there already is a method/property called address in some of SDK classes, and it happens to return NSData *.
NSArray's objectAtIndex: returns an object of type id, and the compiler doesn't know that it's your custom class that has address defined to return NSString *. When it tries to match address selector, it takes the one from SDK, and not yours.
You can however cast the returned object to your class and have your method address called:
[(YourClass *)[LocationData objectAtIndex:rowDisplay] address];
You don't see the warning when outputting address to NSLog since %# format accepts both NSString * and NSData * (for classes other than NSString it actually outputs the result of description method, which returns NSString *).

there is many follow up questions with your question. However, you said, you can show with :
NSLog(#"%#",[[LocationData objectAtIndex:rowDisplay] address]);
so why not use this into UILabel :
self.displayAddress.text = [NSString stringWithFormat:#"%#"[[LocationData objectAtIndex:rowDisplay] address]];
PS: please don't use image for 1 line of code. i have to retype your code here...

Related

Strange behavior of NSString

I have a NSString that will be passed as a parameter to my library's function, the NSString is passed by another library. The strange thing is, if I pass the NSString to the library call, the call will fail, but if I convert the NSString to int and then convert the int back to a NSString, every thing is fine.
But by printing it out using NSLog("%#"), the two strings are identical. What may cause this? Encoding?
When you
convert the NSString to int and then convert the int back to a NSString
you are basically creating a copy of the string, unrelated to the original one.
It would be interesting to know how you create the two strings to know what exactly happens. My guess is that the first one is deallocated too soon, so the call fails; the copy is retained and the call succeeds.
Just for a quick try:
when calling the function that is failing:
[self doMethodWithString:aString];
just do:
[aString retain];
[self doMethodWithString:aString];
If this works, then the memory management issue is confirmed, but for a real fix you should explain how you create the strings...

Sending message to objectForKey to NSMutableArray instance, And it works!! Strange?

I have a very bad code written in my program, was just playing around as I am learning Objective C and iOS platform. What I did is,
I have created NSMutableArray like this,
placeInfo = [NSMutableArray array];
and than later in my code I am doing something like this, basically I am manipulating Google places api response(JSON).
NSDictionary *results = [responseString JSONValue];
placeInfo = [results objectForKey:#"result"];
self.phoneNumber = (NSString *)[placeInfo objectForKey:#"formatted_phone_number"]; // In this line compiler warns me that NSMutableArray might not response to this.
I checked documentation but I didn't find objectForKey in NSMutableArray.
So what could be the reason? Why my code isn't crashing? Why it is returning phone number by "formatted_phone_number" key?
EDIT
After first answer I have edited my code and added type casting like this, but it still works.
NSDictionary *results = [responseString JSONValue];
placeInfo = (NSMutableArray *)[results objectForKey:#"result"];
self.phoneNumber = (NSString *)[placeInfo objectForKey:#"formatted_phone_number"];
I’ve never used the Google Places API, but I’d guess [results objectForKey:#"result"] actually returns another dictionary, so the objectForKey: works.
Because objective-c just uses pointers to refer to objects, it’s never actually being converted to an NSMutableArray. Also, objective-c doesn't know at compile time if a method will exist, due to its dynamic nature (you can actually add methods and even whole classes at runtime).
Depending on the compiler settings, it may just show a warning that objectForKey: might not be found at runtime, and let it continue compiling anyway. It ends up working just fine if you actually passed it an NSDictionary.
Even when you put the (NSMutableArray *) cast in front of it, it won’t change anything. That simply casts the pointer type, and doesn’t actually change the object in any way.
It's doing this because [results objectForKey:#"result"] is returning you something that is not an NSMutableArray. That something that's being returned is likely another NSDictionary which, of course, does respond to objectForKey: To find out what you've got, set a breakpoint after result = [placeInfo objectForKey:#"result"] and inspect result. The debugger will tell you what kind of object you're dealing with. I'll bet you anything you like that it's an NSDictionary.
Objective C allows you to send any message (called a selector) to any object at any time; the runtime does not care whether a particular object implements a given selector. If the target object does not respond to a given selector it will ignore it. It will not crash. In this respect it's utterly unlike most other OOP languages, including C++ and Java, which will fail to compile if you try to call a method that a particular class doesn't implement. You can find out if an object responds to a given selector (which is analagous to using introspection to see if a given class implements a certain method) by saying [result respondsToSelector:#selector(objectForKey:)]. This difference between methods and messages is critically important to understanding Objective C. I'd recommend reading The Objective C Programming Language before doing anything else.
Also, Objective C's type system is less stringently enforced than those other languages. It's quite legal (although a very bad idea) to do what you have done here, which is to declare a pointer of type NSMutableArray and then assign it to (I'm guessing) an NSDictionary.

NSlog returns NULL for NSMutableDictionary from different class

Really confused with why this is not working.
PracticeTeamSelection.m
NSLog(#"Practice Roster : %#", practiceRoster);
PracticeActual.m
PracticeTeamSelection *teamSelectionViewController = [[PracticeTeamSelection alloc]init];
NSLog(#"practice List : %#", [teamSelectionViewController practiceRoster]);
So practiceRoster is an NSMutableDictionary, and when i run the first bit of code I am returned exactly what i am supposed to be, however when i run the next bit of code in PracticeActual.m it returns (Null).
in my PracticeTeamSelection in the .h I do the following with the proper synthesize
#property(nonatomic,retain) NSMutableDictionary *practiceRoster;
and in the PracticeActual.m in include
#import "PracticeTeamSelection.h"
But maybe it is being release somewhere with out my knowledge. Does anyone have any thoughts?
Thanks
You haven't actually created a dictionary anywhere. You just defined a property. All properties on an object start out with their zero value — for objects, this is nil.
You have one PracticeTeamSelection object where practiceRoster is set to something. But in your PracticeActual class, when you write [[PracticeTeamSelection alloc]init], you're creating another PracticeTeamSelection object. The new object has nothing to do with the other one that has its practiceRoster set, no more than all your NSString objects have the same content.

Modifying original data from detailView?

I'm working on iPhone and I'm using navigation.
I have list of data in RootViewController, and pass one data to detailViewController when a cell is clicked. Like this,
detailViewController.message = [tableData objectAtIndex:indexPath.row];
And I want to modify the content of 'message' in detailViewController. Is that possible?
I've tried that, but I get an error that it's immutable object. How can I do that? Somebody give me a hint. Thanks ;)
Added ------------------------------------------------
Ok. I'll specify the question.
in detailViewController, the message is decleared NSMutableDictionary* type.
and used like this.
NSMutableString *str = [m_message objectForKey:KEY_CONTENT];
[str appendFormat:#"appended!"];
And I've got this message.
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendFormat:'
Can't I just modify it's content like modifying data in c++ using pointer?
I think it would be best to use a delegate pattern for this. Create a DetailViewControllerDelegate protocol that informs its delegate of a changed message. Something along the lines of:
-(void)detailViewController:(DetailViewController *)controller didChangeMessage:(NSString *)message;
You could also directly manipulate the object by using a mutable one (NSMutableString, NSMutableArray etc.), but using a delegate improves reusability and decouples your classes.
EDIT:
The fact that your dictionary is mutable doesn't mean the object inside it are mutable as well. Your string str is probably immutable. Since NSMutableString is a subclass of NSString, the assignment will work though. You should make sure that you put a mutable string in the dictionary, or use the mutableCopy method of NSString to get a mutable copy of it.
It depends on what type of object you are passing. Immutable means that you cant alter the object. If you for exaple use NSArray, you have to switch to NSMutableArray instead. The same for string or dictionary.
Okay, i think i figured it out. The documentation for appendFormat says that appendFormat is for appending objects, just like when you use stringWithFormat.
The documentation states that:
The appended string is formed using
NSString's stringWithFormat: method
with the arguments listed.
You should use appendString to get the result you want.

Correctly debugging IPhone Apps on XCode

The line below has an error, can you see it with a naked eye?
NSString *title = [sender titleForState:UIControlStateNormal];
NSString *newText = [[NSString alloc] initWithFormat:"%# button pressed.", title];
When the Iphone simulator executes this line it crashes without any other information. I must be missing something about debugging. The console showed me nothing.
I was able to figure out the error, my question is not about that. My question is why I get a hard crash with no help from XCode. Without any clue it took me precious 5 minutes before I could realize my typo.
Any suggestions? Or when programming for IPhone I just need to be very careful with typos?
EDIT: I guess some people did not see it immediately like me. The error is the lack of '#' for the string constant. So now my question is why XCode/Simulator did not show me any kind of error message, just crashed without any clues. Am I missing something about debugging?
Objective-C does not strongly verify that the arguments you pass to messages are of the right type during compilation nor at runtime. It should gives you a warning though. Here you pass a c string instead of a NSString. Because NSString are objects (thus referenced using pointer), your method uses it as a pointer while you feed it with a simple string. You then probably try to access unaccessible memory blocks...
I think you miss a # before the "%# button pressed".
The correct one should be:
NSString *newText = [[NSString alloc] initWithFormat:#"%# button pressed.", title];
All the constant NSString should be #"SOMETHING HERE";
Check you compilation warnings. That's all you need. On the case you are showing, you will get a proper warning that will alert you that bad things might happen at that line.
I get the following Error when compiling your code:
error: cannot convert 'const char*' to 'NSString*' in argument passing
Not sure what you need to do to get it to show you that, I'm working in Obj-C++.
Try adding "-Wall" to your "OtherWarningFlags" under your target's build settings.