I want to create a wrapper around the NSURLSession and I found some nice code but was written in Swift.https://github.com/daltoniam/SwiftHTTP.But since I still write production code in Objective-C I started borrowing the idea of the above code, though I have hard time to understand the following code and translate to Objective-C (if needed).
I know I could use AFNetworking but this is not feasible due to architecture decisions when building a distributable framework.
The code:
/// encoding for the request.
public var stringEncoding: UInt = NSUTF8StringEncoding
// Somewhere in a method
var charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding));
if request.valueForHTTPHeaderField(contentTypeKey) == nil {
request.setValue("application/x-www-form-urlencoded; charset=\(charset)",
forHTTPHeaderField:contentTypeKey)
}
request.HTTPBody = queryString.dataUsingEncoding(self.stringEncoding)
My Objective-C code:
#property (assign, nonatomic) NSUInteger stringEncoding;
// In this line I get a compiler warning and in runtime it crashes with BAD_EXC
CFStringEncoding cfStringEncoding = CFStringConvertIANACharSetNameToEncoding(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding));
if (![mutableRequest valueForHTTPHeaderField:ContentTypeKey])
{
[mutableRequest setValue:[NSString stringWithFormat:#"application/x-www-form-urlencoded; charset=%u", (unsigned int)cfStringEncoding] forHTTPHeaderField:ContentTypeKey];
}
mutableRequest.HTTPBody = [queryString dataUsingEncoding:self.stringEncoding];
Compiler warning:
Incompatible integer to pointer conversion assigning to 'CFStringEncoding' (aka 'unsigned long') from 'CFStringRef' (aka 'const struct __CFString *')
I don't have strong experience working with CFStringEncoding and CFString so I find it hard to translate the documentation.
Do I really need this conversion, and what is it's purpose?
Try using NSString instead:
NSString *charset =
(NSString *)CFStringConvertEncodingToIANACharSetName
(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
This is what typically was used before the Swift version, and as I recall AFNetworking used a similar method (if not the same).
Related
When reading the headers of Foundation I found this:
- (__strong const char *)UTF8String NS_RETURNS_INNER_POINTER;
// Convenience to return null-terminated UTF8 representation
This is from NSString.h in the iOS 7.1 SDK, what does __strong const char * mean here?
I'm most confused about the "__strong" here.
Foundation is shared between iOS and Mac OS. On Mac OS, for a while there existed a garbage collection memory management system. It's now deprecated and not longer supported on Mac OS. It was never used on iOS.
GC used __strong as a modifier on plain pointer type declarations to make the pointed to memory collectible. This usage of __strong has no meaning in ARC or manual retain/release code. The fact that there's no warning for the declaration is probably only because clang issues no warnings in system headers.
NS_RETURNS_INNER_POINTER is a Clang annotation that indicates the method returns a pointer to one of its inner data structures (i.e., an instance variable), and that inner variable is not reference-counted, so whenever that method is called, ARC should increment the retain count for the receiver (because that object should not be released as long as the pointer to its inner data structures is in use).
In this case, __strong essentially acts in conjunction with NS_RETURNS_INNER_POINTER to indicate the lifetime of an object that returned a pointer to its inner data structures.
__strong means that the object (of class NSString in this case), that holds the pointer, retains its ownership till the end of the life of the object and the pointed memory will be garbage-collected. Hence INNER.
const char * means that the char array this pointer points to is constant, i.e. cannot be changed for example by changing some characters in it (you will get a compiler error).
If you try to compile this:
#import <Foundation/Foundation.h>
int main(int argc, char **argv)
{
NSString *s = #"string";
const char *str = [s UTF8String];
printf("%s\n", str);
str[0] = 'S';
printf("%s\n", str);
return 0;
}
you'll get read-only variable is not assignable error.
After updating Xcode to version 5.1, I had a warning that told me I had defined a constant that I wasn't using. Its definition looked like this:
static NSInteger const ABCMyInteger = 3;
I was happy to see that it got marked, because I thought this meant that the compiler was now able to check for unused constants in addition local to variables.
I refactored some more, making three NSString constants obsolete. All three were defined very similarly to the NSInteger from above:
static NSString *const ABCMyString = #"ABCMyString";
To my surprise, however, these do not get marked as "unused", though I know for sure that they aren't used anymore.
Can someone explain why an NSInteger does get noticed by the compiler as unused, but an NSString does not?
A primitive variable is just a memory block allocated in a static memory part and initialized by the compiler. The string object, however, is a variable initialized at runtime (in startup, probably), so the compiler adds an implicit call to the constructor and uses the variable as a parameter for that call. So the variable is being used.
The _unused item of the structure is IMHO not a directive, but just a member variable, probably it is added for better alignment (fills the object size to a round size).
The definition of an NSString literal at compile time rely on the use of the NSSimpleCString meta class.
This class looks something like this:
#interface NSSimpleCString : NSString {
#package
char *bytes;
int numBytes;
#if __LP64__
int _unused;
#endif
}
#end
#interface NSConstantString : NSSimpleCString
#end
The addition of the _unused flag make me believe that further down the implementation of NSSimpleCString the code will instruct the compiler to silence those warnings with __unused.
You can try yourself by prepending your integer or float constant with __unused like:
__unused static const NSInteger ABCMyInteger = 3;
For a more in depth explanation read the article on literals by Mike Ash
I am trying to convert a CFUUIDRef to a NSString *.
Before, I used the following code, and worked fine.
CFStringRef str = CFUUIDCreateString(NULL, _uuid); # _uuid is of type CFUUIDRef
return (__bridge NSString *) str;
However, after a recent update on Xcode (or other thing that I didn't notice?), the above code gives me the error:
Use of undeclared identifier '__bridge'
So have I did something wrong? How could I solve it?
=== UPDATED ===
The full code:
+ (NSString *)uuidToString:(CFUUIDRef)_uuid {
CFStringRef str = CFUUIDCreateString(NULL, _uuid); # _uuid is of type CFUUIDRef
return (__bridge NSString *) str;
}
The uuid is generated by:
uuid = CFUUIDCreate(NULL);
__bridge is only defined with ARC (Automatic Reference Counting) enabled. It is used to "transfer objects in and out of ARC control". (Source)
To turn on ARC, go to your build settings and set Objective-C Automatic Reference Counting to Yes.
Or, if you do not want to use ARC, simply remove __bridge and it should work fine.
In Objective-C, I can write:
id pString = #"Hello, World.";
and the compiler will instantiate an NSString without me needing to explicitly call a factory method. However, NSString is really just a Foundation class and thus presumably not part of the actual Objective-C language definition.
So when I write #"String", how does the compiler know to build an NSString in particular, and not some other string-like object? In other words, where does the Objective-C language stop and the Foundation library start?
When you write Objective-C code outside of Cocoa or GNUStep environments, #"..." is not linked to NSString.
In this case, gcc provides an option for specifying a class associated to literal strings:
-fconstant-string-class=class-name
Use class-name as the name of the class to instantiate for each
literal string specified with the syntax "#"..."". The default
class name is "NXConstantString".
The #"" directive appears to be built-in to the objective-c compiler.
For instance, if you remove all #imports from your .m source file (& prefix header), the following line will be a syntax error:
NSString *string = #"ABCD"; // (Doesn't know anything about NSString class)
However, if you change the Foundation NSString type to the built-in void type, it will compile just fine:
void *string = #"ABCD";
So, even without Foundation's NSString definition, the compiler knows how to turn #"" into something that can become an NSString instance at runtime (it probably won't instantiate without Foundation, but the compiler doesn't seem to mind); Since it accepts the syntax without needing any external library definitions, the compiler sees #"" as part of the language.
Your code, however, won't be able to make use of any #"" instance without importing Foundation.h, so from the point of view of your program, #"" is part of the library.
Another interesting bit is that an Objective-C string literal (#"" notation) returns the same type as an explicitly instantiated NSString object:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
printf("string literal class: %s\n", object_getClassName(#"a string literal"););
NSString *str = [[NSString alloc] initWithUTF8String:"asdf"];
printf("explicit NSString class: %s", object_getClassName(str));
[pool drain];
return 0;
}
I vaguely remember that in other, older implementations of Objective-C, the string literal actually returned an object of a slightly different class, but that could be used interchangeably with NSString/NSCFString. Not totally sure on that part, though.
I am trying to write a function which returns a string created from two input strings;
but when I try the function declaration
NSString Do_Something(NSString str1, NSString str2)
{
}
the compiler gets sick. (Worked fine for a different function with int arguments.)
If I change the input arguments to pointers to strings, in also gets sick.
So how do I pass Objective-C objects into a function?
All Objective-C objects being passed to functions must be pointers. Rewriting it like this will fix your compiler error:
NSString *Do_Something(NSString *str1, NSString *str2) { }
Also, please keep in mind that this is a (C-style) function and not an instance method written on an Objective-C object. If you wanted this to actually be a method on an object it would probably look something like this:
NSString *doSomethingWithString1:(NSString *)str1 string2:(NSString *)str2 { }
I say "probably" because you can name it however you want.
Functions are perfectly fine in Objective-C (and in fact earn some of the language's benefits).
See my answer to C function always returns zero to Objective C, where someone was trying what you are and had a problem with the compiler assuming return type. The structure that I set up there is important when you are using functions, just like when you are using objects and methods. Be sure to get your headers right.
To be pedantic, you're using a function definition of:
NSString *DoSomething(NSString *str1, NSString *str2) {
// Drop the _ in the name for style reasons
}
And you should be declaring it in a .h file like so:
NSString *DoSomething(NSString *str1, NSString *str2);
Just like C.
that doesn't work for me. i've just declared in the .h:
NSString *myFunction(NSDecimal *value);
and i type in the .m:
NSString *myFunction(NSDecimal *value){
//code
}
but always i get an error saying expected '(' before '*' token
now is fixed. for some reason... sorry.