Get the data stored in address using the * operator - ios

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.

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);

Objective-C passing object to function is always by reference or or by value?

In objective-c I am passing NSMutableDictionary to function and modifying it inside function it returns modified mutable dictionary :
NSMutableDictionary *obj2 = [[NSMutableDictionary alloc]initWithObjectsAndKeys:#"hello",#"fname",nil];
[self callerDictionary:obj2];
NSLog(#"%#",obj2[#"fname"]);//printing "Hi"
-(void)callerDictionary:(NSMutableDictionary*)obj
{
obj[#"fname"] = #"Hi";
}
Technically, Objective C always passes parameter by value, as does C, but practically when you pass an object you need to pass a pointer. While this pointer is passed by value, the semantics of Objective-C give the same effect as if you had passed an object reference; if you modify the objected that is pointed to by the pointer then you are modifying the same object instance that is pointed to in the calling context. The common terminology used in Objective C programming is "object reference" even though it is really a pointer value.
You can see from the * in the method signature that it is a pointer (or object reference in the common usage). If you are passing an intrinsic type, such as an int then it is passed by value unless you explicitly declare the method as requiring a reference:
For example:
-(void) someFunction:(int *)intPointer {
*intPointer = 5;
}
would be called as
int someInteger = 0;
[self someFunction: &someInteger];
// someInteger is now 5
The distinction between a pointer value and a true object reference can be seen in comparison to Swift which uses true references;
If I have
-(void)someFunction:(NSString *)someString {
int length = [someString length];
}
and then do
NSMutableArray *array = [NSMutableArray new];
[someFunction: (NSString *)array];
I will get a runtime exception since array doesn't have a length method, but the compiler can't confirm the type I am passing since it is a pointer.
If I attempted the equivalent in Swift then I will get a compile time error since it knows that the type coercion will always fail
All objects in Objective C passed by reference.
All C types such as NSUInteger, double etc. passed by value
C and Objective-C always pass parameters by value. Objective-C objects are always accessed through a reference (i.e. a pointer). There is a difference between a variable type (int, pointer, etc.) and the way variables are passed as function parameters. The use of the term reference in both scenarios can cause confusion.
by-value:
void f(int a) {
a = 14;
}
int a = 5;
NSLog(#"%d", a); // prints: 5
f(a);
NSLog(#"%d", a); // prints: 5
The value 5 is printed both times because the function f() is given a copy of the value of a, which is 5. The variable referenced within the function is not the same variable that was passed in; it is a copy.
In C++, you can have functions that take parameters by reference.
by-reference:
void f(int &a) {
a = 14;
}
int a = 5;
NSLog(#"%d", a); // prints: 5
f(a);
NSLog(#"%d", a); // prints: 14
Note the & in the function signature. In C++ (but not C, nor Objective-C), this means that the parameter is passed by reference. What this means is that a reference (pointer) to a is passed to the function. Within the function, the a variable is implicitly dereferenced (remember, it's really a pointer, but you don't treat it as one), and the original a variable declared outside the function is changed.
In C and Objective-C, passing a pointer to a function is functionally equivalent to using a reference parameter in C++. This is because a copy of the address is given to the function (remember, the parameter is still passed by value), and that address points to the same object instance that the original pointer does. The reason you don't see any explicit pointer dereferencing within the function (similar to the C++ reference) is because Objective-C syntax for object access always implicitly dereferences -- being within a function doesn't change this behavior.

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.

#encoding for type id where id is actually any object

I have a following method.
- (void)someObject:(id)obj {
char* encoding = #encoding(typeof(obj));
NSString *s = [NSString stringWithCString:encoding encoding:NSUTF8StringEncoding];
NSLog(s);
}
this method always return #"#" whether I pass a variable of type NSNumber, NSArray, NSDictionary or NSString in obj. I assume it is checking the obj pointer type.
What do I have to do so that it returns the actual type encoding of the variable that I have passed?
#encode() is a compile-time construct; it only knows about the variable's type, not the class of the object that will be contained in the object at runtime. Any object-typed variable will encode to #.
You will have to use runtime checks, asking the objects for their classes, to accomplish your goal.

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

Resources