- •C and Objective-C
- •How this book works
- •How the life of a programmer works
- •Installing Apple’s developer tools
- •Getting started with Xcode
- •Where do I start writing code?
- •How do I run my program?
- •So what is a program?
- •Don’t stop
- •Types
- •A program with variables
- •Challenge
- •Boolean variables
- •When should I use a function?
- •How do I write and use a function?
- •How functions work together
- •Local variables, frames, and the stack
- •Recursion
- •Looking at the frames in the debugger
- •return
- •Global and static variables
- •Challenge
- •printf()
- •Integer operations
- •Integer division
- •Operator shorthand
- •Floating-point numbers
- •Tokens for displaying floating-point numbers
- •The while loop
- •The for loop
- •break
- •continue
- •The do-while loop
- •Challenge
- •Getting addresses
- •Storing addresses in pointers
- •Getting the data at an address
- •How many bytes?
- •NULL
- •Stylish pointer declarations
- •Challenges
- •Writing pass-by-reference functions
- •Avoid dereferencing NULL
- •Creating and using your first object
- •Message anatomy
- •Objects in memory
- •Challenge
- •Nesting message sends
- •Multiple arguments
- •Sending messages to nil
- •Challenge
- •Challenge
- •NSMutableArray
- •Reference pages
- •Quick Help
- •Other options and resources
- •Accessor methods
- •Dot notation
- •Properties
- •self
- •Multiple files
- •Challenge
- •Overriding methods
- •super
- •Challenge
- •Object ownership and ARC
- •Creating the Asset class
- •Adding a to-many relationship to Employee
- •Challenge
- •Retain cycles
- •Weak references
- •Zeroing of weak references
- •For the More Curious: Manual reference counting and ARC History
- •Retain count rules
- •NSArray/NSMutableArray
- •Immutable objects
- •Sorting
- •Filtering
- •NSSet/NSMutableSet
- •NSDictionary/NSMutableDictionary
- •Preprocessor directives
- •#include and #import
- •#define
- •Global variables
- •enum
- •#define vs global variables
- •Writing an NSString to a file
- •Reading files with NSString
- •Writing an NSData object to a file
- •Reading an NSData from a file
- •Target-action
- •Helper objects
- •Notifications
- •Which to use?
- •Callbacks and object ownership
- •Challenge
- •Getting started with iTahDoodle
- •BNRAppDelegate
- •Adding a C helper function
- •Objects in iTahDoodle
- •Model-View-Controller
- •The application delegate
- •Setting up views
- •Running on the iOS simulator
- •Wiring up the table view
- •Adding new tasks
- •Saving task data
- •For the More Curious: What about main()?
- •Edit BNRDocument.h
- •A look at Interface Builder
- •Edit BNRDocument.xib
- •Making connections
- •Revisiting MVC
- •Edit BNRDocument.m
- •Writing init methods
- •A basic init method
- •Using accessors
- •init methods that take arguments
- •Deadly init methods
- •Property attributes
- •Mutability
- •Lifetime specifiers
- •copy
- •More about copying
- •Advice on atomic vs. nonatomic
- •Key-value coding
- •Non-object types
- •Defining blocks
- •Using blocks
- •Declaring a block variable
- •Assigning a block
- •Passing in a block
- •typedef
- •Return values
- •Memory management
- •The block-based future
- •Challenges
- •Anonymous block
- •NSNotificationCenter
- •Bitwise-OR
- •Bitwise-AND
- •Other bitwise operators
- •Exclusive OR
- •Complement
- •Left-shift
- •Right-shift
- •Using enum to define bit masks
- •More bytes
- •Challenge
- •char
- •char *
- •String literals
- •Converting to and from NSString
- •Next Steps
- •Index
Using enum to define bit masks
Every time you right-shift a number one place, you half its value. (If it is odd, round down.)
Using enum to define bit masks
Often you will want to define a list of constants, each representing an integer with one bit turned on. Then, these integers can be bitwise-ORed together and tested for using bitwise-AND, as described above.
The elegant way to do this is to define an enum that uses the left-shift operator to define the values. Here is how the constants for the UIDataDetector are defined:
enum { |
|
|
UIDataDetectorTypePhoneNumber |
= 1 |
<< 0, |
UIDataDetectorTypeLink |
= 1 |
<< 1, |
UIDataDetectorTypeAddress |
= 1 |
<< 2, |
UIDataDetectorTypeCalendarEvent |
= 1 |
<< 3, |
UIDataDetectorTypeNone |
= 0, |
|
UIDataDetectorTypeAll |
= NSUIntegerMax |
|
}; |
|
|
More bytes
In this chapter, we worked with unsigned char, which is one 8-bit byte. Any unsigned integer type will work the same way. For example, NSTextCheckingTypePhoneNumber is actually declared uint64_t, a 64-bit unsigned number.
Challenge
Write a program that creates an unsigned 64-bit integer such that every other bit is turned on. (There are actually two possible resulting numbers: one is even, the other is odd. Create the odd one.) Display the number.
245
This page intentionally left blank
34
C Strings
Given the choice, an Objective-C programmer will always choose to work with NSString objects rather than C strings. However, sometimes we don’t have a choice. The most common reason we end up using C strings? When we access a C library from within our Objective-C code. For example, there is a library of C functions that lets your program talk to a PostgreSQL database server. The functions in that library use C strings, not instances of NSString.
char
In the last section, we talked about how a byte could be treated as a number. We can also treat a byte as a character. As mentioned earlier, there are many different string encodings. The oldest and most famous is ASCII. ASCII (American Standard Code for Information Interchange) defines a different character for each byte. For example, 0x4b is the character ‘K’.
Create a new C Command Line Tool and name it yostring. In this program, you are going to list some of the characters in the ASCII standard. Edit main.c:
#include <stdio.h>
int main (int argc, const char * argv[])
{
char x = 0x21; // The character '!'
while (x <= 0x7e) { // The character '~' printf("%x is %c\n", x, x);
x++;
}
return 0;
}
You may be wondering “Hey, a byte can hold any one of 256 numbers. You just printed out 94 characters. What happened to the to the rest?” It is important to realize that ASCII was written to drive old teletype-style terminals that printed to paper instead of to a screen. For example, the number 7
in ASCII makes the terminal bell ring. In fact, the characters 0 - 31 in ASCII are unprintable control codes. Number 32 is the space character. Number 127 is the delete – it causes the previous character to disappear. What about characters 128 – 255? ASCII only uses 7 bits. There is no ASCII character for the number 128.
You can use ASCII characters as literals in code. Just put them inside single quotes. Change your code to use these:
247
Chapter 34 C Strings
int main (int argc, const char * argv[])
{
char x = '!'; // The character '!'
while (x <= '~') { // The character '~' printf("%x is %c\n", x, x);
x++;
}
return 0;
}
Build it and run it.
The non-printable characters can be expressed using escape sequences that start with \. You’ve already used \n for the newline character. Here are some common ones:
Table 34.1 Common escape sequences
\n |
new line |
|
|
\t |
tab |
|
|
\' |
single-quote |
|
|
\" |
double-quote |
|
|
\0 |
null byte (0x00) |
|
|
\\ |
backslash |
|
|
char *
A C string is just a bunch of characters right next to each other in memory. The string ends when the character 0x00 is encountered.
Figure 34.1 The word “Love” as a C string
Functions that take C strings expect the address of the string’s first character. strlen(), for example, will count the number of characters in a string. Try building a string and using strlen() to count the letters:
248
char *
#include <stdio.h> // For printf
#include <stdlib.h> // For malloc/free #include <string.h> // For strlen
int main (int argc, const char * argv[])
{
char x = '!'; // The character '!'
while (x <= '~') { // The character '~' printf("%x is %c\n", x, x);
x++;
}
//Get a pointer to 5 bytes of memory on the heap char *start = malloc(5);
//Put 'L' in the first byte
*start = 'L';
//Put 'o' in the second byte *(start + 1) = 'o';
//Put 'v' in the third byte *(start + 2) = 'v';
//Put 'e' in the fourth byte *(start + 3) = 'e';
//Put zero in the fifth byte *(start + 4) = '\0';
//Print out the string and its length
printf("%s has %zu characters\n", start, strlen(start));
// Print out the third letter
printf("The third letter is %c\n", *(start + 2));
// Free the memory so that it can be reused free(start);
start = NULL;
return 0;
}
Build and run it.
Notice the places where you added a pointer and a number together. start is declared to be a char *. A char is one byte. So start + 1 is a pointer one byte further in memory than start. start + 2 is two bytes further in memory than start.
Figure 34.2 The address of each character
249