读书笔记

Objective-C Programming: The Big Nerd Ranch Guide (2nd Edition)

  • When you run a program, a file is copied from the file system into memory (RAM), and the instructions in that file are executed by your computer.

  • The very lowest-level programming language is called assembly code.

  • The life of a programmer is mostly a never-ending struggle. Solving problems in an always-changing technical landscape means that programmers are always learning new things.

  • Most professional programmers learn to struggle hour after hour, day after day, without getting (too) frustrated. This is another skill that will serve you well.

  • Anything that is executable on a computer we call a program. Some programs have graphical user interfaces; we call these applications.Some programs have no graphical user interface and run for days in the background; we call these daemons.Some programs have no graphical user interface and run for a short time in the terminal; we call these command-line tools.

  • A function is a list of instructions for the computer to execute, and every function has a name.

  • Code is the set of instructions that tell the computer to do something.

  • Comments are ignored by the computer, but we programmers use them to document code we have written.

  • Syntax is the set of rules that governs how code must be written in a given programming language.

  • A program is a collection of functions. A function is a list of operations for the processor to execute.

  • When you write a program in C (which is relatively pleasant for you), the compiler converts your program’s functions into machine code (which is pleasant and efficient for the processor).

  • As we get older, we are baffled much less often – not because we know everything, but because we tend to steer away from things that leave us bewildered.

  • A place where one piece of data can go is known as a variable.

  • In a program, you create a new variable by declaring its type and name.

  • An expression is something that gets evaluated and results in some value.

  • In C, it was decided that 0 would represent false, and anything that is not zero would be considered true.

  • A function is a name associated with a chunk of code.

  • Values passed to a function are known as arguments. The argument’s value is then assigned to the corresponding parameter name. That parameter name can be used inside the function as a variable that contains the passed-in value.

  • Partitioning your code into functions makes it easier to make changes and to find and fix bugs. You can make a change or fix a typo in one place, and it will have the effects you want everywhere you call that function.

  • A program is a collection of functions. When you run a program, those functions are copied from the hard drive into memory, and the processor finds the function called “main” and executes it.

  • Local variables are variables declared inside a function.They exist only during the execution of that function and can only be accessed from within that function.A function can have many local variables, and all of them are stored in the frame for that function. Think of the frame as a blackboard that you can scribble on while the function is running. When the function is done executing, the blackboard is discarded.

  • Programmers use the word stack to describe where the frames are stored in memory.

  • When a function is called, its frame is pushed onto the top of the stack. When a function finishes executing, we say that it returns. That is, it pops its frame off the stack and lets the function that called it resume execution.

  • You can use the debugger to browse the frames on the stack.

  • When you return 0 to the system, you are saying “Everything went OK.” If you are terminating the program because something has gone wrong, you return 1.

  • A static variable is like a global variable in that it is declared outside of any function.

  • A static variable is only accessible from the code in the file where it was declared.

  • Your computer is, at its core, a processor (the Central Processing Unit or CPU) and a vast meadow of switches (the Random-Access Memory or RAM) that can be turned on or off by the processor. We say that a switch holds one bit of information. You will often see 1 used to represent “on” and 0 used to represent “off.”

  • Eight of these switches make a byte of information.

  • The processor can fetch the state of these switches, do operations on the bits, and store the result in another set of switches.

  • The address of a variable is the location in memory where the value for that variable is stored.

  • Memory addresses are nearly always printed in hexadecimal format.

  • Notice that the asterisk is used two different ways in this example:

  • When you declared addressOfI to be an int *. That is, you told the compiler “It will hold an address where an int can be stored.”

  • When you read the int value that is stored at the address stored in addressOfI. (Pointers are also called references. Thus, using the pointer to read data at the address is sometimes called dereferencing the pointer.)

  • Sometimes you need a pointer to nothing. That is, you have a variable that can hold an address, and you want to store something in it that makes it explicit that the variable is not set to anything. We use NULL for this

  • What is NULL? Remember that an address is just a number. NULL is zero.
  • A typedef defines an alias for a type declaration and allows you to use it more like the usual data types.
  • So far, your programs have used one kind of memory – frames on the stack. Recall that every function has a frame where its local variables are stored. This memory is automatically allocated when a function starts and automatically deallocated when the function ends. In fact, local variables are sometimes called automatic variables because of this convenient behavior.
  • Sometimes, however, you need to claim a contiguous chunk of memory yourself – a buffer. Programmers often use the word buffer to mean a long line of bytes of memory. The buffer comes from a region of memory known as the heap, which is separate from the stack.
  • You request a buffer of memory using the function malloc(). When you are done using the buffer, you call the function free() to release your claim on that memory and return it to the heap.
  • A framework is library of classes that you use to write programs.
  • An object is similar to a struct (such as the struct Person you created in Chapter 11). Like a struct, an object can contain several pieces of related data. In a struct, we called them members. In an object, we call them instance variables (or you might hear “ivars”).
  • An object differs from a struct in that an object can also have its own functions that act on the data it contains. These functions are called methods.
  • A class defines a kind of object. It also produces objects of that kind. You can think of a class as both blueprint and factory.
  • What is the difference between #import and #include? #import is faster and more efficient.
  • In Objective-C, to execute the code in a method, you send a message to the object or class that has that method.
  • A message send is surrounded by square brackets and has two parts: the receiver and the selector.
  • Why 1970? OS X and iOS are based on Unix, and 1970 is the start of the “Unix epoch.”
  • Typically, class methods create an instance of the class and initialize its instance variables.
  • Typically, instance methods give you information about or perform an operation on an instance’s instance variables.
  • Message sends can be nested.
  • When message sends are nested, the system will handle the message send on the inside first and then the message that contains it.
  • The alloc method is a class method that every class has. It returns a pointer to a new instance that needs to be initialized. An uninitialized instance may exist in memory, but it is not ready to receive messages. The init method is an instance method that every class has. It initializes an instance so that it is ready to work.
  • Nearly all object-oriented languages have the idea of nil, the pointer to no object.
  • They really are the same thing: the zero pointer. By convention, though, we use nil when referring to the value of an empty pointer declared as pointing to an Objective-C object type, and NULL when referring to any other pointer, such as to a struct.
  • When Objective-C was designed, it was decided that sending a message to nil would be OK; it would simply do nothing.
  • Important thing #1: If you are sending messages and nothing is happening, make sure you are not sending messages to a pointer that has been set to nil.
  • Important thing #2: If you send a message to nil, the return value is meaningless and should be disregarded.
  • Notice that there is no asterisk in this declaration. id implies the asterisk.
  • Objects can only be accessed via a pointer,
  • However, is important to remember that the pointer and the object that it points at are not the same thing. Here is a more accurate statement: “now is a pointer that can hold an address of a location in memory where an instance of NSDate lives.”
  • If you lose your only pointer to an object, then you can no longer access it – even if it continues to exist on the heap.
  • When we talk about memory management, we are talking about managing heap memory.
  • The stack is an orderly stack of frames. Each frame is automatically deallocated when the function using it ends. The heap, on the other hand, is a heaping pile of memory, and that is where your objects live.
  • “reference” is another word for pointer
  • Each object keeps a count of how many references to itself there are. When this reference count reaches zero, the object knows it is no longer needed and will self-destruct.
  • When your project has ARC enabled, the compiler adds code to your project to tell each object when it gains or loses a reference.
  • As long as you have a pointer to an object, you can be sure that it will continue to exist.
  • You can only add or remove a reference to the object. The object will destroy itself when its reference count reaches zero.
  • An object also loses a reference when the pointer variable itself is destroyed.
  • To insert non-ASCII characters, use \u followed by the Unicode number for that character in hexadecimal.
  • An instance of NSMutableArray is similar to an instance of NSArray, but you can add, remove, and reorder pointers. (NSMutableArray is a subclass of NSArray.
  • Remember that a class describes objects in two ways: instance variables within each instance of the class and methods implemented by the class.
  • In object-oriented thinking, however, code that is outside of a class should not directly read or write to the instance variables of an instance of that class. Only code within the class can do that.
  • A getter method, or getter, allows code outside of a class to read, or get, the value of an instance variable.
  • A setter method, or setter, allows code outside of a class to change, or set, the value of an instance variable.
  • Setter and getter methods are collectively known as accessor methods, or simply accessors.
  • Self is a pointer to the object that is running the method. It is used when an object wants to send a message to itself.
  • Properties are either atomic or nonatomic. The difference has to do with multithreading, which is a topic beyond the scope of this book. All of the properties that you will declare in this book will be nonatomic.
  • Sometimes a class needs a “read-only” property – a property whose value can be read but not changed. A property like this should have a getter method but no setter method. You can instruct the compiler to create only a getter method by including a readonly value in the list of property attributes.
  • However, you did not have to include the readwrite attribute because readwrite is the default value. Default values are optional in declarations.
  • Practically speaking, whenever you declare a property that points to an NSString or an NSArray, you should include the copy attribute.
  • It is critical to remember, however, that when using dot notation with an object, a message is being sent.
  • You override an inherited method by writing a new implementation.
  • when you override a method, you can only change its implementation. You cannot change how it is declared; the method’s name, return type, and argument types must stay the same.
  • Every object’s isa pointer points at the class that created it.
  • When you send a message to an object, you kick off a search for a method of that name. The search follows the object’s isa pointer to start looking for the method in the object’s class. If there is no method of that name there, then it is on to the superclass. The hunt stops when the method is found or when the top of the hierarchy (NSObject) is reached.
  • When you use the super directive, you are sending a message to the current object but saying, “Run a method with this name, but start the search for its implementation at your superclass.”
  • An object instance variable points to another object and describes a relationship between the two objects.
  • Objects do not live inside other objects. The employee object contains its employee ID (the variable and the value itself), but it only knows where its spouse lives in memory.
  • There are two important side-effects to objects pointing to – rather than containing – other objects:
  • One object can take on several roles.
  • You end up with a lot of distinct objects using up your program’s memory. You need the objects being used to stay around, but you want the unnecessary ones to be deallocated (have their memory returned to the heap) so that their memory can be reused.
  • When an object has an object instance variable, the object with the pointer is said to own the object that is being pointed to.
  • When an object has zero owners, it figures no one needs it around anymore and deallocates itself.
  • The header is where a class advertises its properties and methods so that other objects will know how to interact with it.
  • Some properties or methods may only be intended for use by the class or instances of the class. Such internal details are better declared in a class extension. A class extension is a set of declarations that is private. Only the class or instances of the class are able to use the properties, instance variables, or methods declared in a class extension.
  • A subclass has no access to its superclass’s class extensions.
  • When a class declares a property in its header, only the accessors for this property are visible to other objects.
  • Strong reference cycles are a very common source of memory leaks.
  • How do you fix a strong reference cycle? Use a weak reference. A weak reference is a pointer that does not imply ownership.
  • In a parent-child relationship, the general rule for preventing this type of strong reference cycle is the parent owns the child, but the child should not own the parent.
  • A strong reference will keep the object it points to from being deallocated. A weak reference will not. Thus instance variables and properties that are marked as weak are pointing at objects that might go away. If this happens, that instance variable or property will be set to nil, instead of continuing to point to where the object used to live.
  • Sets are faster at testing object membership than arrays are.
  • An NSSet is immutable — you cannot add or remove objects after the set has been created. NSMutableSet is the subclass that adds the ability to add and remove objects from a set.
  • Identical objects are always equal. Equal objects are not always identical.
  • Using an immutable collection conserves memory and improves performance because that collection never needs to be copied.
  • An immutable collection also claims ownership of its objects, but the immutability of the collection means that all the objects in the collection are owned when the collection is created and disowned when the collection is deallocated.
  • What is the difference between #include and #import? #import ensures that the preprocessor only includes a file once. #include will allow you to include the same file many times. C programmers tend to use #include. Objective-C programmers tend to use #import.
  • When you use #define to do function-like stuff instead of simply substituting a value, you are creating a macro.
  • A pointer comparison is faster than a message send and scanning two strings character-by-character
  • A callback lets you write a piece of code and then associate that code with a particular event. When the event happens, your code is executed.
  • In Objective-C, there are four forms that a callback can take:
    • Target-action: Before the wait begins, you say “When this event happens, send this message to this object.” The object receiving the message is the target. The selector for the message is the action.
    • Helper objects: Before the wait begins, you say “Here is an object that will take on a role that helps another object do its job. When one of the events related to this role occurs, send a message to the helper object.” Helper objects are often known as delegates or data sources.
    • Notifications: There is an object called the notification center. When an event happens, a notification associated with that event will be posted to the notification center. Before the wait begins, you tell the notification center “This object is interested in this kind of notification. When one is posted, send this message to the object.”
    • Blocks: A block is a just a chunk of code to be executed. Before the wait begins, you say “Here is a block. When this event happens, execute this block.”
  • When sending one callback to one object, Apple uses target-action. When sending an assortment of callbacks to one object, Apple uses a helper object with a protocol. These helper objects are typically called delegates or data sources.
  • Objects that do just one thing (like NSTimer) use target-action.
  • Objects that have more complicated lives (like an NSURLConnection) use helper objects, and the most common type of helper object is the delegate.
  • Objects that might need to trigger callbacks in several other objects (like NSTimeZone) use notifications.
  • A block is a chunk of code.
  • You can pass a block as an argument to a method that accepts a block. Many of Apple’s classes have methods that accept blocks as arguments.
  • Blocks, on the other hand, keep the code to be triggered by an event close by.
  • An anonymous block is a block that you pass directly to a method without assigning it to a block variable first.
  • At their deepest darkest cores, objects are actually structs.
  • Don’t access instance variables directly. Use your accessors!
  • the class of an object is different from its role in a working system.
  • A protocol can specify a role that an object can fill.
  • The compiler considers an object to have successfully conformed to a protocol if the object has implemented all of the protocol’s required methods.
  • A GUI-based application is event-driven. When the application is launched, it starts a run loop that sits and waits for events. Events can be generated by the user (like a button tap) or by the system (like a low-memory warning). When an event happens, the application leaps into action to respond to the specific event. All iOS applications are event-driven applications.
  • The “app delegate” is the starting point of an application, and every iOS application has one.
  • Model-View-Controller, or MVC, is a design pattern that is based on the idea that any class that you create should fall into one of three job categories: model, view, or controller.
  • When an iOS application first launches, a lot of setup is happening behind the scenes. An instance of UIApplication is created to control the application’s state and act as liaison to the operating system. An instance of BNRAppDelegate is also created and set as the delegate of the UIApplication instance (which explains the name “app delegate”).
  • A control is a view that the user can interact with.
  • This statement tells you that IBAction is replaced with void before the compiler sees it. All IBAction keywords can replaced with void because actions invoked by user interface controls are not expected to have a return value.
  • “Outlet” is just another word for “object pointer.”
  • You send the init message to the new instance so that it can initialize its instance variables to usable values; alloc creates the space for an object, and init makes the object ready to work. Notice that init is an instance method that returns the address of the initialized object. It is the initializer for NSObject.
  • In the first line of init, you set self to point to the object returned from the superclass’s init method.
  • You check that the superclass’s initializer returns a valid object and not nil.
  • The init method figures out a clever optimization that it can do, deallocates the original object, allocates a different object, and returns the new object.
  • To address this possibility, Apple requires that you set self to point to the object returned from the superclass’s initializer.
  • The init method fails, deallocates the object, and returns nil.
  • To deal with this possibility, Apple recommends that you check that the superclass’s initializer returns a valid object and not nil. After all, there is no point in performing custom set-up on an object that does not exist.
  • When you create a subclass, you typically only need to initialize the instance variables that the subclass introduced; let the superclass take care of the instance variables that it introduced.
  • The designated initializer acts as a funnel-point. A class has only one designated initializer method. If the class has other initializers, then the implementation of those initializers must call (directly or indirectly) the designated initializer.
    • If a class has several initializers, only one should do the real work. That method is known as the designated initializer. All other initializers should call, either directly or indirectly, the designated initializer.
    • The designated initializer will call the superclass’s designated initializer before initializing its instance variables.
    • If the designated initializer of your class has a different name than the designated initializer of its superclass, you must override the superclass’s designated initializer so that it calls the new designated initializer.
    • If you have several initializers, clearly document which is the designated initializer in the header.
  • A property can be declared readwrite or readonly. The default is readwrite, which means that both a setter and a getter method are created. If you do not want a setter method to be created, you mark the property as readonly
  • A property can also be declared unsafe_unretained, assign, strong, weak, or copy. This option determines how the setter handles the property’s memory management.
  • assign is the default for non-object types and the simplest: it just assigns the passed-in value to the property
  • You will always use assign for properties that hold non-objects. Because it is the default for non-object types, you do not have to add it to your property declaration.
  • strong, as you learned in Chapter 23, will ensure that a strong reference is kept to the passed-in object. It will also let go of ownership of the old object (which will then deallocate itself if it has no other owners).
  • For object properties, strong is the default for object pointers, and that is usually what you want.
  • weak does not imply ownership of the object pointed to. If this object is deallocated, then the property will be set to nil.
  • A dangling pointer points to an object that no longer exists. Sending a message to a dangling pointer usually crashes your program.
  • unsafe_unretained properties, like weak properties, do not imply ownership. However, an unsafe_unretained property is not automatically set to nil when the object that it points to is deallocated.
  • The copy option makes a copy of an object and then changes the pointer to refer to this copy.
  • Use of the copy attribute is most common with object types that have mutable subclasses.
  • What if the object passed in is not mutable? It seems wasteful to make a copy of an immutable object. The copy method just calls copyWithZone: and passes nil as the argument.
  • For objects that come in mutable and immutable versions, the copy method returns an immutable copy. For example, NSMutableString has a copy method that returns an instance of NSString. If you want the copy to be a mutable object, use the mutableCopy method.
  • the nonatomic option will make your setter method run a tiny bit faster.
  • You should always make your readwrite properties nonatomic
  • There are two reasonable cases to implement an accessor yourself:
    • You need to update the app’s user interface when the change occurs.
    • You need to update some cached info when the change occurs.
  • If you declare a property and implement both accessors yourself, the compiler will not synthesize an instance variable.
  • Key-value coding is the ability to read and set a property using its name. The key-value coding methods are defined in NSObject, and thus every object has this capability.
  • Key-value observing is a technique that lets you get a notification when a particular property of an object changes.
  • When you add yourself as an object’s observer, you specify the name of the property you are observing. You can also specify some options. In particular, you can tell the object to send you the old and/or new value of the property when you are notified of the change.
  • Categories let a programmer add methods to any existing class.
  • When you implement a method using a category, it replaces any method with the same name that already exists on the class.
  • You should use categories to add functionality to existing classes. Do not use them to replace functionality in existing classes; use subclassing instead.