stringWithUTF8string returns null - ios

I tried to solve my issue for a week and the only hope is for You!
I receive from a user a string via uitextview and cast it using next code:
unsigned char* pAr = [myuitextview.text UTF8string];
Then after some work i want to show resulting pAr in the myuitextview using this code:
Myuitextview.text = [NSString stringWithUTF8string:pAr];
As result i see blank myuitextview.
After investigation i discovered,that stringWithUtf8string returns nil, but i received it in utf8 and create back with utf8.
Then i discovered that UTF8string
returns nil also.
Also i discovered that it happens when i use unsigned char* instead of const char* returned by utf8string method. When i receive to const char* it returns a c string but if i try unsigned char* it returns nil.
What can be the reason of null after stringwithutf8string? As i understand Unsigned char * and const char* are safe casts?

You can't so easily transfer unsigned char to NSString
Try this one
NSString* s = [[NSString alloc] initWithBytes:pAr length:sizeof(pAr) encoding:NSASCIIStringEncoding];

NSString has a method "UTF8String" (note the use of caps")
I don't see a method "utf8string" (all lower case). Where does that method come from? (Objective-C method names are case sensitive, so those are differennt method names.)
Also, note that in the docs for UTF8String say:
The returned C string is a pointer to a structure inside the string object, which may have a lifetime shorter than the string object and will certainly not have a longer lifetime. Therefore, you should copy the C string if it needs to be stored outside of the memory context in which you called this method.
If you use that method you meed to make sure that your text field sticks around and that you don't change it's string contents or the pointer you get back from the UTF8String method will become invalid.

Related

How do I convert NSString to an encoding other than UTF-8?

I'm working with c in iOS Project I'm trying to convert my string to respected type in c , below code is supposed to send to core Library
typedef uint16_t UniCharT;
static const UniCharT s_learnWord[] = {'H', 'e','l','\0'};
what i have done till now is string is the one what I'm passing
NSString * string = #"Hel";
static const UniCharT *a = (UniCharT *)[string UTF8String];
But it is failing to convert when more than one character , If i pass one character then working fine please let me where i miss, How can i pass like s_learnWord ?
and i tried in google and StackOverFLow none of the duplicates or answers didn't worked for me like this
Convert NSString into char array I'm already doing same way only.
Your question is a little ambiguous as the title says "c type char[]" but your code uses typedef uint16_t UniCharT; which is contradictory.
For any string conversions other than UTF-8, you normally want to use the method getCString:maxLength:encoding:.
As you are using uint16_t, you probably are trying to use UTF-16? You'll want to pass NSUTF16StringEncoding as the encoding constant in that case. (Or possibly NSUTF16BigEndianStringEncoding/NSUTF16LittleEndianStringEncoding)
Something like this should work:
include <stdlib.h>
// ...
NSString * string = #"part";
NSUInteger stringBytes = [string maximumLengthOfBytesUsingEncoding];
stringBytes += sizeof(UniCharT); // make space for \0 termination
UniCharT* convertedString = calloc(1, stringBytes);
[string getCString:(char*)convertedString
maxLength:stringBytes
encoding:NSUTF16StringEncoding];
// now use convertedString, pass it to library etc.
free(convertedString);

Get the data stored in address using the * operator

int i = 17;
int *addressOfI = &i;
printf("the int stored at addressOfI is %d\n", *addressOfI);
The question is: If I can get the data stored in addressOfI using the * operator, why it doesn't works for type NSString? like following:
NSString *string = #"Hello world!"
printf("the NSString stored at string is %#\n", *string);
why it doesn't works for type NSString?
Because NSString is an Objective-C object and not a primitive type. The NSString * pointer actually points to a struct objc_object which provides the framework for the object system. You can probably "see" some primitive types within this framework (i.e. members of objc_object) however it's supposed to be a black box to normal developers.
The actual reason your second piece of code will crash is that the %# format specifier expects to call the description method on the object you pass in as an argument and you have dereferenced that object pointer so it's no longer a valid object pointer.

How to Convert NSValue to NSString

Some background... I am writing code that interacts with javascript via a ObjC-JS bridge utilizing UIWebView's stringByEvaluatingJavaScriptFromString:. The idea is that the "brains" of the app be in JS which tells Objective-C how to behave. There are multiple benefits to this like reduced binary size, flexible updates, etc. However, there is a case where there is some Objective-C only object that the JS needs to have a reference to (JS instructs ObjC when to use/remove the object). This is being done by placing the native object in a dictionary with a unique identifier which can be passed as a string to JS (over the bridge). My problem stems with coming up with a nice identifier for said native Objective-C object.
Thus, I am trying to convert a reference to an object to a string with no luck. This is what I have:
// anObject is a custom class
NSValue *handle = [NSValue valueWithPointer:(__bridge const void *)anObject];
NSData *data = [NSData dataWithValue:handle];
NSString *stringHandle = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
The dataWithValue: function (taken from this SO post):
+ (NSData *)dataWithValue:(NSValue *)value {
NSUInteger size;
const char* encoding = [value objCType];
NSGetSizeAndAlignment(encoding, &size, NULL);
void* ptr = malloc(size);
[value getValue:ptr];
NSData* data = [NSData dataWithBytes:ptr length:size];
free(ptr);
return data;
}
Walking through it in the debugger shows me a nil value for stringHandle:
What am I doing wrong?
What you're doing wrong is trying to treat an address as if it's a UTF-8 encoded string. An address -- or any other chunk of arbitrary data -- isn't very likely to be valid UTF-8 data. (If by chance it were, it still wouldn't be the string you expect.)
If you're trying to get a string containing the pointer value, i.e., the address of the original object, that's just [NSString stringWithFormat:#"%p", anObject];
If you really need to do it from the NSValue, then replace anObject with [theValue pointerValue].
If you want to pretty-print arbitrary data, see How to convert an NSData into an NSString Hex string?
You can get a string representation by calling the NSObject method "description". You can override the "description" method in a subclass if you need.
An NSValue of a pointer will be an object holding the 4 bytes of the 32-bit pointer. It will not hold any of the data pointed to in RAM.

Assigning pointer in Objective C or C

NSHost *instance = [NSHost currentHost];
NSString *answer = [instance localizedName];
NSLog(#"%#",answer);
Ok, I know the basics of pointer but I have some doubts on this 3 line of code. After posting a similar question on this website, still the answer i got doesn't really answer my question.
So, first of all,
I know that pointer needs to hold an address.
But why don't we do something like this?
NSHost*instance=&[NSHost currentHost];
adding &. This is because only & shows the address of something.
2nd question what does
[NSHost currentHost]
return
does it return address of its instance?
IF not how can we assign NSHost*instance=[NSHost currentHost]; its wrong.
third question,
I know that NSString *answer = [instance localizedName]; returns an instane of NSString because its written in a book and I'm using it now to complete the challenge in the book.
in this code NSString *answer = [instance localizedName]
are we assigning a pointer to a pointer?? because [instance localizedName] returns a pointer of NSString.
When teaching Objective-C classes, I use this analogy to explain the (somewhat confusing) concept of pointers:
1) When you create an uninitialized variable, like int val;, it creates a "bucket" that can hold an integer value. The bucket itself has a memory address.
2) When you assign a value to the variable with val = 5;, you put that value into the bucket:
3) A pointer variable (one with a leading asterisk *) like int *ptr; is a "bucket", that does not contain a value, but the memory address of another "bucket":
4) To a pointer variable you assign not the value that is contained in another bucket, but the memory address of that other bucket. You get the "bucket address" of a value's bucket by putting the & (ampersand) character in front of the variable name:
That being said, when a method already returns a pointer variable (like NSString *), you already get the memory address and don't have to ask for it again by using &.
To bring the point home, in this example, we have 2 buckets:
NSString *text = #"Test";
The first bucket contains the value (#"Test"), the second bucket contains the memory address of the first bucket. Or, to use the bucket analogy again: #"Test" is in the left bucket, and the right bucket (the variable text) contains the memory address of the left bucket. We can see that by running this:
NSLog(#"value: %#, bucket that contains value: %p, bucket that contains the memory address of the bucket containing the value: %p", text, text, &text);
// output: value: Test, bucket that contains value: 0x1032f5030, bucket that contains the memory address of the bucket containing the value: 0x7fff5c90bb68
Hope this helps!
You don't add a &, because currentHost already returns a pointer. Check out its header:
+ (NSHost *)currentHost
It returns an NSHost* and you assign it to an NSHost*.
[NSHost currentHost] will return a pointer to a specific instance of NSHost.
Same thing here. localizedName returns a pointer to an NSString (NSString*) and you assign it to one.
1) & 2)
NSHost *instance = [NSHost currentHost]; returns a pointer of NSHost object.
So there is no need to put & before [NSHost currentHost].
In C language:
int *ptr = NULL;
int iVar;
You need to assign the address like:
ptr = &iVar;
If both are pointers:
int *ptr = NULL;
int *iVar = NULL;
You can assign the pointer like:
ptr = iVar;
This is what you are doing in the following code also:
NSHost *instance = [NSHost currentHost];
3)
NSString *answer = [instance localizedName]; here also the same thing is happening. The localizedName returns a pointer of NSString

EXC_BAD_ACCESS error when using NSString getCString

I'm trying to parse some HTML. I use stringWithContentsOfURL to get the HTML. I attempt to load this into a character array so I can parse it, but I crash with the EXC_BAD_ACCESS error when getCString is called. Here is the relavent code:
- (void)parseStoryWithURL:(NSURL *)storyURL
{
_paragraphs = [[NSMutableArray alloc] initWithCapacity:10];
_read = NO;
NSError* error = nil;
NSString* originalFeed = [NSString stringWithContentsOfURL:storyURL encoding:NSUTF8StringEncoding error:&error];
_i = originalFeed.length;
char* entireFeed = malloc(_i*sizeof(char));
char* current = entireFeed;
char* lagger;
char* recentChars = malloc(7);
BOOL collectRecent = NO;
BOOL paragraphStarted = NO;
BOOL paragraphEnded = NO;
int recentIndex = 0;
int paragraphSize = 0;
NSLog(#"original Feed: %#", originalFeed);
_read = [originalFeed getCString:*entireFeed maxLength:_i encoding:NSUTF8StringEncoding];
I've also tried this passing the 'current' pointer to getCString but it behaves the same. From what I've read this error is typically thrown when you try to read from deallocated memory. I'm programming for iOS 5 with memory management. The line before that I print the HTML to the log and everything is fine. Help would be appreciated. I need to get past this error so I can test/debug my HTML parsing algorithms.
PS: If someone with enough reputation is allowed to, please add "getCString" as a tag. Apparently no one uses this function :(
There are several issues with your code - you're passing the wrong pointers and not reserving enough space. Probably the easiest is to use UTF8String instead:
char *entireFeed = strdup([originalFeed UTF8String]);
At the end you'll have to free the string with free(entireFeed) though. If you don't modify it you can use
const char *entireFeed = [originalFeed UTF8String];
directly.
If you want to use getCString, you'll need to determine the length first - which has to include the termination character as well as extra space for encoded characters, so something like:
NSUInteger len = [originalFeed lengthOfBytesUsingEncoding: NSUTF8StringEncoding] + 1;
char entireFeed[len];
[originalFeed getCString:entireFeed maxLength:len encoding:NSUTF8StringEncoding];
Try explicitly malloc'ing entireFeed with a length of _i (not 100% certain of this, as NSUTF8String might also include double byte unichars or wchars) instead of the wacky char * entireFeed[_i] thing you're doing.
I can't imagine char * entireFeed[_i] is working at run-time (and instead, you're passing a NULL pointer to your getCString method).
A few strange things;
char* entireFeed[_i]; allocates an array of char*, not an array of char. I suspect you want char entireFeed[_i] or char *entireFeed = malloc(_i*sizeof(char));
getCString takes a char* as a first parameter, that is, you should send it entireFeed instead of *entireFeed.
Also, note that the (UTF-8) encoding may add bytes to the result, so allocating the buffer the exact size of the input may cause the method to return NO (buffer too small). You should really use [originalFeed UTF8String] instead.

Resources