See Also
Last week's iPad Friday
Hello and happy Friday. Today's iPad wallpapers continue our study in Light and Shadow. Enjoy!Last week's iPad Friday
(click an image for the full-size wallpaper)
NSString
literal. Today we'll take a quick overview of wide character strings and talk about where they fit into the iOS development.char
value. By the time C was first standardized by ANSI in 1989 (and by ISO in 1990), the need to handle many more characters than ASCII was obvious, but the Unicode standard was still nascent. So the ANSI C committee included a wide character type and wide character string functions in the C89 standard, but didn't tie wide character support to any specific character encoding scheme.wchar_t
wchar_t
. This is similar to a char
, but typically "wider". On many systems, including Windows, a wchar_t
is 16 bits. This is typical of systems that implemented their Unicode support using earlier versions of the Unicode standard, which originally defined fewer than 65,535 characters. Unicode was later expanded to support historical and special purpose character sets, so on some systems, including Mac OS X and iOS, the wchar_t
type is 32 bits in size. This is often poorly documented, but you can use a simple test like this to find out:// how big is wchar_t? NSLog(@"wchar_t is %u bits wide", 8 * sizeof(wchar_t));On a Mac or iPhone, this will print "wchar_t is 32 bits wide". Additionally,
wchar_t
is a typedef
for another integer type in C. In C++, wchar_t
is a built-in integer type. In practice, this means you need to #include <wchar.h>
in C when using wide characters.char
integer type is almost always a signed integer with a range from -128 to 127. You can use the CHAR_MIN
and CHAR_MAX
constants defined in <limits.h>
to find out the range for a particular compiler:NSLog(@"CHAR_MIN = %0.f", (double)CHAR_MIN); NSLog(@"CHAR_MAX = %0.f", (double)CHAR_MIN);
wchar_t
type can be signed or unsigned. The WCHAR_MIN
and WCHAR_MAX
constants hold the range of a wchar_t
and are defined in both <wchar.h>
and <stdint.h>
.NSLog(@"WCHAR_MIN = %0.f", (double)WCHAR_MIN); NSLog(@"WCHAR_MAX = %0.f", (double)WCHAR_MIN);On Windows,
wchar_t
is an unsigned 16-bit integer. On Mac and iPhone, wchar_t
is a signed 32-bit integer, so the code above will print out "WCHAR_MAX = 2147483647" and "WCHAR_MIN = -2147483648". For the most part you don't need to worry about whether wchar_t
is signed or unsigned; it only becomes important if you need to do comparisons and operations that mix wchar_t
with other integer types (a rarity).// example of a wide character string literal wchar_t const *s = L"foobarf!";Like C string literals, wide strings separated by only whitespace are considered one logical string:
// wide strings written in segments wchar_t const *s1 = L"foo" "bar"; wchar_t const *s2 = L"Hello, " L"world!";
<string.h>
header. A very similar set of functions for wide character strings are defined in <wchar.h>
. The functions follow a similar naming convention. Where string functions are prefixed with str
, the wide character equivalents are prefixed with wcs
(for wide character string). So the strlen()
function calculates the length of a string and the corresponding wcslen()
function calculates the length of a wide character string.NSString
class does just about everything wide character strings are meant to do, but you may occasionally run across them in other C libraries.NSString
s, starting with string concatenation.
UIImageView
respond to a tap or other gesture and it's being stubborn and just ignoring you, make sure you've set userInteractionEnabled
to YES
. You can do this programmatically after the UIImageView
is created or loaded or in the Attributes Inspector pane in Interface Builder if the UIImageView
is defined in a NIB file. Naturally, userInteractionEnabled
defaults to NO
.
NSString
literals. Today we'll continue this topic by looking at embedding Unicode characters in literals using Unicode escape sequences.NSString
literals) with Mac OS X 10.5. The C99 standard actually refers to these escape sequences as universal character names since C doesn't require that the compiler use a particular character set or encoding scheme, but iOS and most modern systems use the Unicode character set so we'll continue to call them "Unicode escapes".// Examples of Unicode escapes char const *gamma1 = "\u0393"; // capital Greek letter gamma (Γ) NSString *gamma2 = @"\U00000393"; // also ΓUnlike hexadecimal escape sequences, Unicode escapes are required to have four or eight digits after the 'u' or 'U' respectively. If you have too few digits, the compiler generates a "incomplete universal character name" error.
char
data type can only hold a character value from zero to 255, what does the compiler do when it encounters a capital gamma (Γ) with a Unicode character value of 915 (or 393 in hex)? The C99 standard leaves this up to the compiler. In the version of GCC that ships with Xcode and the iOS SDK, the answer is UTF-8 encoding.char const *gamma1 = "\u0393";the compiler has no way to encode that logical character in a single
char
. We would expect thatNSLog(@"%u", strlen(gamma1));would print
1
for the length of the string, but it actually prints 2
.Address | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
---|---|---|---|---|---|---|---|---|---|
Value | 206 | 147 | 206 | 181 | 206 | 181 | 206 | 186 | 0 |
Character | 'Γ' | 'ε' | 'ε' | 'κ' | '\0' |
char
s) each. (And other characters may use three or four bytes.) The standard C strlen()
function actually counts char
s (or bytes) in the string rather than logical characters, which made perfect sense in 1970 when computers used ASCII or another single byte character set like Latin-1.NSString
literals suffer from a similar problem. Internally, NSString
uses 16 bit words to encode each character. This made sense when NSString
was created, since early versions of the Unicode standard only encoded up to 65,535 characters, so a 16 bit word value could hold any Unicode character (at the time).NSString
.// NSString sometimes has a misleading "length"
NSString *gClef = @"\U0001d11e"; // musical G clef symbol (𝄞)
NSLog(@"%u", [gClef length]);
The log statement prints out 2
instead of 1
.NSString
data looks like this:Address | 64 | 65 | 66 | 67 | 68 | 69 |
---|---|---|---|---|---|---|
Value | 0xD834 | 0xDD1E | 0 | |||
Character | '𝄞' | '\0' |
strlen()
function for C strings, the -length
method actually returns the number of words in the NSString
, which is usually but not always the number of logical characters in the NSString
object.NSString
literals.// what does this print out? char message[7] = { 105, 80, 104, 111, 110, 101, 0 }; printf(message);Geek points if you recognized that
message
is a null terminated string. Super ultra mega geek points if you can read what it says (hint: it's ASCII).NSString
literals. They look like this:// C string literal char const *s1 = "Hello, world!"; // NSString literal NSString *s2 = @"Hello, world!";The double quote characters (") mark the beginning and the end of the string literal.
NSString
literals are prefixed with @
to distinguish them from C string literals. It's important not to mix the two up; they're not directly compatible.// not a legal string literal char const *s1 = "Hello, world! How are you?";Line breaks are not allowed inside the double quotes in a string literal. To include a line break, you use the new line (\n) escape sequence. We'll talk more about escape sequences below, but using the new line escape sequence, the string literal becomes:
// string literal containing a new line char const *s1 = "Hello, world!\nHow are you?";Notice that the new line escape sequence takes the place of an actual line break in the code. When the compiler sees "\n" in a string literal, it replaces it with ASCII character code 10, the line feed (or new line) character.
char const *error1 = "Unable to complete request: please wait a few minutes and try again."; char const *error2 = "Unable to complete request: \ please wait a few minutes and try again.";This works for
NSString
literals also, but note that any leading space in the continuation line will be interpreted as part of the string. Also note that the backslash (\) must be directly before the line break in the code; if you have any space or tab characters between the backslash and the line break, the compiler will complain.char const *error1 = "Unable to complete request: please wait a few minutes and try again."; char const *error2 = "Unable to complete request: " "please wait a few minutes and try again.";This also works for
NSString
literals; only the first part of an NSString
literal is prefixed with @
:NSString *error1 = @"Unable to complete request: please wait a few minutes and try again."; NSString *error2 = @"Unable to complete request: " "please wait a few minutes and try again.";Only spaces, tabs and line breaks are allowed between sections of a string literal. If the string is supposed to have a line break at the end of each section, you need to add new line escapes:
char const *error_page = "<html>\n" " <head><title>404 Not Found</title></head>\n" " <body>\n" " <h1>404 Not Found</h1>\n" " </body>\n" "</html>\n";
escape sequence | name | ASCII value |
---|---|---|
\n | new line or line feed | 10 |
\r | carriage return | 13 |
\t | tab | 9 |
\" | double quote | 34 |
\\ | backslash | 92 |
// octal escape sequence examples char const *bell = "\7"; // ASCII code 7 (bell) char const *bs = "\10"; // ASCII code 8 (backspace) char const *del = "\177"; // ASCII code 127 (delete)The octal numbers in escape sequences are limited to three digits; you can pad short octal numbers with leading zeros:
char const *bell = "\007";which is handy to format a long sequence of octal escapes. Also note that octal numbers must be between 0 and 255. Octal escapes greater than 255 (377 octal) will be interpreted in a surprising way:
// max octal value is 377 (255 decimal) char const *two55 = "\377"; NSLog(@"length = %u", strlen(two55)); NSLog(@"first char = %u", (unsigned char)two55[0]); // prints: // length = 1 // first char = 255 // octal value of 378 (256 decimal) isn't a valid escape char const *two56 = "\378"; NSLog(@"length = %u", strlen(two56)); NSLog(@"first char = %u", (unsigned char)two56[0]); NSLog(@"second char = %u", (unsigned char)two56[1]); // prints: // length = 2 // first char = 31 (octal 37) // second char = 56 (ASCII code for '8')Because the compiler will try to read up to three octal digits, an octal escape with fewer than three digits can sometimes have an unexpected interpretation. For example, embedding a form feed character (ASCII code 12, octal 14) at the start of this string produces the expected string:
char const *heading = "\14Preface"; NSLog(@"first char = %u", (unsigned char)title[0]); NSLog(@"second char = %u", (unsigned char)title[1]); // prints: // first char = 12 (form feed, octal value 14) // second char = 80 (ASCII code for 'P')But if the character directly after '\14' is a valid octal digit, the compiler produces something unintended:
char const *heading = "\141. Introduction"; NSLog(@"first char = %u", (unsigned char)title[0]); NSLog(@"second char = %u", (unsigned char)title[1]); // prints: // first char = 97 (octal value 141) // second char = 46 (ASCII code for '.')The heading number '1' is a valid octal digit, so the compiler assumes it's part of the octal escape. There are several ways to prevent this. You can use an escape sequence to specify the ambiguous character, break the string into parts, or simply pad the octal number with leading zeros.
// dealing with ambiguous octal escapes // replace possible octal characters with escapes char const *heading1 = "\14\61. Introduction"; // '\61' is octal escape for '1' // pad octal escape to three digits char const *heading2 = "\0141. Introduction"; // unambiguous // break string into parts char const *heading3 = "\14" "1. Introduction"; // easier to read
// hexadecimal escape sequence examples char const *tab = "\x09"; // ASCII code 9 (horizontal tab) char const *newline = "\xA"; // ASCII code 10 (new line/line feed) char const *del = "\x7f"; // ASCII code 127 (delete)The upper hexadecimal digits (represented by A through F) can be upper or lower case.
char const *title = "\xcThe C Language"; NSLog(@"first char = %u", (unsigned char)title[0]); NSLog(@"second char = %u", (unsigned char)title[1]); // prints: // first char = 12 (form feed, hex value c) // second char = 84 (ASCII code for 'T')Since 'T' isn't a valid hex digit, the compiler figures out that the first character is '\xc'. The following string doesn't work as expected:
char const *title = "\xcC Language Primer"; NSLog(@"first char = %u", (unsigned char)title[0]); NSLog(@"second char = %u", (unsigned char)title[1]); // prints: // first char = 204 (hex value cc) // second char = 32 (ASCII code for space)Since 'C' is a valid hex digit, the compiler sees the first character as '\xcC' (cc in hex, 204 in decimal) and the second character as the space after the 'C'. To prevent this, you can replace any ambiguous character with an escape sequence, or better yet simply break the string into parts.
// dealing with ambiguous hexadecimal escapes // replace possible hex characters with escapes char const *title1 = "\xc\103 Language Primer"; // '\103' is octal escape for 'C' // break string into parts char const *title2 = "\xc" "C Language Primer"; // much easier to readAs in octal escapes, the hexadecimal number in a hexadecimal escape is limited to the range of 0 through 255. If you specify a hexadecimal escape sequence larger than 255, the compiler will emit a "hex escape sequence out of range" warning.
iAd's "click-through" rate is something like five times higher, and its effective cost-per-thousand-impressions (ECPM) is around 300 times greater than offered by Android's system.It will be interesting if other developers report similar revenue rates and if iAds continue to deliver after the novelty has worn off.
A new law is about to go into effect in San Francisco requiring sellers of mobile phones to post the “Specific Absorption Rate” (SAR) levels of the devices. How will conveying this information to consumers affect sales of mobile phones and devices—and which manufactures will feel the burden of this new stigma?Check it out!
Places? (NEW) Category: Entertainment Released Jan 4, 2009 Version: 1.0 1.3 MB $0.99 USD |
|
People? (NEW) Category: Entertainment Released Dec 28, 2009 Version: 1.0 1.3 MB $0.99 USD |
|
Orchard's Craps (NEW) Category: Games Released Oct 2, 2009 Version: 1.0 2.9 MB $0.99 USD |
|
Hi Ka Flash (NEW) Category: Education Released Aug 15, 2009 Version: 1.0 1.2 MB $0.99 USD |
|
Fridgemags (NEW) Category: Entertainment Released Jul 24, 2009 Version: 1.0 2.3 MB $0.99 USD |
|
Animals? (UPDATED) Category: Entertainment Released Mar 17, 2009 Version: 1.1 1.4 MB $0.99 USD |