Objective-C Programming: The Big Nerd Ranch Guide (2nd Edition) 阅读笔记(Part III)

• Objects
    ○ An object is similar to a struct, it can contain several pieces of related data.
    In a struct, we called them member.
    In an object, we call them instance variables.(or ivars)
    ○ An object differs from a struct in that an object can also have its own functions that act on the data is contains. These functions are called methods.
    ○ Classes
        § Class - describes a certain type of object by listing the instance variables and methods that object will have. A class can describe an object that represents
            □ A concept, like a date, a string, or a set
            □ Something in the real word, like a person, a location, or a checking account
        § 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.
        § Framework - a set of related classes, functions, constants, and types.
        § The Foundation framework contains fundamental classes that are used in all iOS apps and OS X applications.
        § Difference between #import & #include
            □ #import is faster and more efficient
            □ When the complier sees the #include directive, it makes a dumb copy-and-paste of the contents of the file to include.
            □ When the complier sees the #import directive, it first checks to see if another file may have already imported or included the file.
        § NSLog() is a function in the Foundation framework that is a lot like printf().
        It accepts a format string and can have replaceable tokens.
    ○ Methods and messages
        § Methods are like functions. They contain code to be executed on command.
        In Objective-C, to execute the code in a method, you send a message to the object or class that has that method.

        § 
        § When the date method is executed, the NSDate class claims some memory on the heap for an instance of NSDate, initializes the instances to the current date/time, and returns the address of the new object.
        § %@ - a Objective-C token asks the object for a description of itself
        § Class methods & instance methods
            □ 
            □ You sent the date message to the NSDate class. Date is a class method. Typically, class methods create an instance of the class and initialize its instance variables.
            □ In the second message send, you sent the timeIntervalSince1970 message to the NSDate instance pointed to by now. timeIntervalSince1970 is an instance method. Typically, instance methods give you information about or perform an operation on an instance's instance variables.
            □ Instance methods tend to be more common in Objective-C programs. You send a message to a class to create an instance. This message causes a class method to be executed. But once you have that instance, the instance will likely receive many messages over the run of program. These messages will cause instance methods to be executed.
• More messages
    ○ A message with an argument
        § 
        § When a method has an argument, the colon is an essential part of the method's name.
        There is no method named dateByAddingTimeInterval.
        There is only dateByAddingTimeInterval:.
    ○ Multiple arguments
        § 
        § This method takes three arguments, so its name has three parts, but this is one message send and it triggers one method.
    ○ Nesting message sends
        § When message sends are nested, the system will handle the message send on the inside first and then the message that contains it.
    ○ Alloc and init
        § There is one case where it is always right and proper to nest two message sends.
        You always nest the messages alloc and init.
        § 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.
        § NSDate *now = [NSDate date];
        NSDate *now = [[NSDate alloc] init];
        There is no difference in the two ways of creating an instance of NSDate.
        The init method of NSDate initializes the NSDate object to the current date and time - just like the date method does. The date method is a convenient way to get an NSDate instance with minimal code. In fact, we call this sort of method a convenience method.
    ○ Sending message to nil
        § Nil - the pointer to no object
        § Nil & null 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.
        § Sending a message to nil would be OK; it would simply do nothing.
        Thus, this code is completely legal:
            Dog *fido = nil;
            [fido goGetTheNewspaper];
        § Import 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.
        § Import thing #2: If you send a message to nil, the return value is meaningless and should be disregarded.
    ○ Id
        § You need a way to create a pointer without knowing exactly what kind of object the pointer will refer to.
        For this case , you use the type id to mean "a pointer to some kind of Objective-C object".
        § Here is what it looks like when you use it:
        Id delegate;
        Notice that there is no asterisk in this declaration. Id implies the asterisk.
• Objects and Memory
    ○ Objects can only be accessed via a pointer
    ○ The pointer and the object that it points at are not the same thing
    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.
    ○ Memory management
        § When we talk memory management, we are talking about managing heap memory.
        § Running low on memory is a problem. It will cause a Mac app to perform badly and will cause an iOS app to crash.
    ○ ARC
        § The setting that instructs the complier to ensure the destruction of unreferenced objects is called ARC.
        § ARC is short for Automatic Reference Counting.
        § 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 complier adds code to your project to tell each object when it gains or loses a reference.
        § You will never explicitly destroy an object, as you would a buffer with free().
        You can only add or remove a reference to the object.
        The object will destroy itself when its reference count reaches zero.
        § Setting a pointer to nil causes the object to lose a reference.
        An object also loses a reference when the pointer variable itself is destroyed.
        § Things get a little more complicated when you have objects with instance variables pointing to other objects.
• NSString
    ○ Instance of NSString hold character strings.
    ○ Objective-C developers use NSString instances to hold and manipulate text in their programs.
        § Creating instances of NSString
            □ NSString *lament = @"Why me!?";
            The @"…" is Objective-C shorthand for creating an NSString object with the given character string.
            □ Instance of NSString can contain any Unicode character. To insert non-ASCII characters, use \u followed by the Unicode number for that character in hexadecimal.
            NSString *slogan = @"I \u2661 New York!";
            □ Because NSString objects can hold Unicode characters, they make it easy to create applications that can deal with strings from many languages.
            □ Create strings dynamically - use the stringWithFormat: class method:
                NSString *dateString = [NSString stringWithFormat:@"The date is %@",now];
            In the stringWithFormat: message, you send as an argument a format string with one or more tokens and the variable(s) whose values will be used in place of the token(s).It works the same as the format string that you have been passing to the NSLog function.
    ○ NSString methods
        § "-" at the start of the method means an instance method
        "+" at the start of the method means a class method
        § -(NSUInteger)length;
        NSUInteger charCount = [dateString length];
        § -(BOOL) isEqualToString:(NSString *)other;
        § -(NSString *)uppercaseString;
    ○ Class references
• NSArray
    ○ An instance of NSArray holds a list of pointers to other objects.
    ○ Creating arrays
        NSArray *dateList = @[pointer1,pointer2,pointer3,…];
    ○ An instance of NSArray is immutable. 
    Once an NSArray been created, you can never add or remove a pointer from that array.
    Nor can you change the order of the pointers in that array.
    ○ Accessing arrays
        § Arrays are ordered lists, and you access an item in an array by its index.(Array are zero-based)
        NSArray *dateList = @[pointer1,pointer2,pointer3,…];
        NSLog(@"The first date is %@",dateList[0]);
        NSLog(@"There are %lu dates",[dateList count]);
    ○ Iterating over arrays
        § You can do this with a for-loop.
        § Programmers iterate over arrays so often that they made a special addition to the for-loop called fast enumeration.
            For(NSDate *d in dateList){
                NSLog(@"Here is a date: %@",d);
            }
    ○ NSMutableArray
        § 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.
        §  You used the class method array to create the NSMutableArray. This method returns an empty array, to which you can then add objects. You can also use alloc and init to get the same result:
            NSMutableArray *dateList = [[NSMutableArray alloc] init];
        § addObject: method adds the object to the end of the list.
        § insertObject: atIndex: adds an object at a specific index
        § removeObject: atIndex: remove an object from array
        § When using fast enumeration with an NSMutableArray, you are not allowed to add or remove items while iterating over the array. If you need to add or remove items while iterating, you must use a standard for-loop.
    ○ Old-style array methods
        NSAarray *dateList = [NSArray arrayWithObjects: now, tomorrow,  yesterday, nil];
        NSLog(@"The first date is %@", [dateList objectAtIndex:0]);
• Your First Class
    ○ BNRPerson class, like all Objective-C classes will be defined in two files:
        § BNRPerson.h is the class's header and will contain the declarations of instance variables and methods
        § BNRPerson.m is the implementation file. This is where you write out the code for, or implement, each method.
    ○ A header file starts with @interface and finishes off with @end. Notice that you declared the instance variables first and inside of curly braces.
    ○ By convention, instance variable names start with an underscore("_").
    Using the underscore prefix lets you easily tell instance variables from local variables when reading code.
    The underscore does not mean anything special to the complier; it is simply the first character in the instance variable's name.
    ○ Shortcut moves you back and forth between the header and implementation files of a class: Control-Command-up arrow
    ○ #import  <Foundation/Foundation.h>
    #import  "BNRPerson.h"
    Angled brackets tell the complier that Foundation/Foundation.h is a precompiled header found in Apple's Libraries.
    The quotation marks tell the compiler to look for BNRPerson.h within the current project.
    ○ Accessor methods
        § 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.
        § Instead, a class will provide methods that let external code access the instance variables of an instance.
        A getter method allows code outside of a class to read, or get, the value of an instance variable.
        A setter method allows code outside of a class to change, or set, the value of an instance variable.
    ○ Accessor naming conventions
        § Getter methods are given the name of the instance variable minus the underscore.
        § Setter methods start with set followed by the name of the instance variable minus the underscore.
        Notice that the case of the setter's name adjusts to preserve the camel-casing. Thus, the first letter of the instance variable name is uppercase in the setter's name.
        § The compiler will name the accessors according to these conventions.
    ○ Self
        § Inside any method, you have access to the implicit local variable self.
        § 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.
        § You can also pass self as an argument to let other objects know where the current object is.
    ○ Multiple files
        § When you build the project, executable code files are compiled separately and then linked together.
        § When Xcode builds your project, it compliers each of the .m and .c files into machine code. Then, it links those files together with any libraries into the executable file.
    ○ Class prefixes
        § Objective-C is not namespaced. This means that if you write a program with a class called Person in it, and you link in a library of someone else's code that also declares a Person class, then the compiler will not be able to tell these two classes apart, and you will get a compiler error.
        § To prevent name collisions like this, Apple recommends that you prefix each of your class names with three or more letters, to make your class names more unique and less likely to collide with someone else's class name. Most developers use either their company’s or their project's initials.
• Properties
    ○ Objective-C has a convenient shortcut called properties that lets you skip declaring instance variables and declaring and implementing accessor methods. Using properties simplifies your class's code.
    ○ Declaring properties
        § A property declaration begins with @property and includes the type of the property and its name.
        § When you declare a property, the compiler not only declares your accessors for you, it also implements them based on the property's declaration.
        § The complier created instance variables named _variables1. However, you do not see these variables in your code because there are no longer any explicit accessor implementations. When using properties, you rarely need to use instance variables directly and can rely on the accessors that the compiler created.
        § Apple recommends using properties.
    ○ Property attributes
        § A property declaration can have one or more property attributes.
        Property attributes give the complier more information about how the property should have.
        Property attributes appear in a comma-delitmited list in parentheses after the @property annotation.
        § Properties are either atomic or nonatomic.(atomic is the default value, default values are optional in declaration)
        The difference has to do with multithreading.
        § Property are either readonly or readwrite (readwrite is the default value)
        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 complier to create only a getter method by including a readonly vaule in the list of property attributes.
            @property (nonmatic,readonly) double circumferenceOfEarth;
            @property (nonmatic,readwrite) double humanPopulation;
        § Another attribute that you will see shortly is copy.
        Practically speaking, whenever you declare a property that points to an NSString or an NSArray, you should include the copy attribute.
    ○ Dot notation
        § When properties were introduced, Apple also introduced a shorthand dot notation for calling those accessors.
        § When using dot notation with an object, a message is being sent.
            These two lines do the exact same thing:
                Mikey.weightInKilos = 96;
                [mikey setWeightInkilos:96];
            These two lines do the exact same thing:
                Float w = mikey.weightInKilos;
                Float w = [mikey weightInKilos];
        § Notice that mikey.weightInKilos sends one of two possible messages, depending on the context in which it is being used.
• Inheritance
    ○ When a property points to an object, there are memory management implications.
    ○ An instance of subclass can stand in for an instance of the superclass without problems because it inherits everything in the superclass.
    ○ Overriding methods
        § A subclass needs to do something differently than its superclass. 
        You override an inherited method by writing a new implementation.
        § Do not need declare it in .h file.
        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.
    ○ Super
        § Use super directive to call superclass's version of method
    ○ Inheritance hierarchy
        § All objects inherit (either directly or indirectly) from NSObject:

        NSObject has many methods but only one instance variables: the isa pointer.
        Every object's isa pointer points at the class that created is.
        (When you have a BNRPerson instance, that object "is a" BNRPerson.
         When you have an NSString instance, that object "is a[n]" NSString.)
        § 
        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 hunts stops when the method is found or when the top of hierarchy (NSObject) is reached.
        § The first implementation that is found is the one that gets executed.
        § 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."
    ○ Description and %@
        § The %@ token sends a description message to the object pointed to by the corresponding variable.
        § The description method returns a string that is a useful description of an instance of the class.
        It's an NSObject method, so every object implements it.
        The default NSObject implementation returns the object's address in memory as a string.
• Object Instance Variables and Properties
    ○ It is far more common for instance variables to be pointers to other objects
    An object instance variable points to another object and describes a relationship between the two objects.
    Usually, object instance variables fall into one of three categories:
        § Object-type attributes: a pointer to a simple, value-like object like an NSString or an NSDate.
        We recommend that you always declare these as a property with an implicit instance variable.
        § To-one relationships: a pointer to a single complex object.
        Once again, we will recommend that you always declare these as a property with an implicit instance variable.
        § To-many relationships: a pointer to an instance of a collection class, such as an NSMutableArray.
        You will often end up explicitly creating instance variables, accessors, and methods adding or removing objects from the relationship.

    ○ Object ownership and ARC
        § When an object has an object instance variable, the object with the pointer is said to own the object that is being pointed to.
        § Because of ARC, an object knows how many owners it currently has.
        When an object has zero owners, it figures no one needs it around anymore and deallocates itself.
        (Before ARC was introduced in Xcode 4.2, we managed ownership manually and spent a lot of time and effort doing so.)
        § There is an NSObject method named dealloc.
        § When an object is added to the collection, the collection establishes a pointer to the object, and the object gains a owner.
        When an object is removed from a collection, the collection gets rid of its pointer to the object, and the object loses an owner.
        § The @class BNRAsset; line tells the complier "There is a class called BNRAsset. Do not panic when you see it in this file."
        Using @class instead of #import gives the compiler less information, but makes the processing of this particular file faster.
        § The property has type NSArray, which tells other classes, "If you ask for my assets, you are going to get something that is not mutable."
        However, behind the scenes, the assets array is actually an instance of NSMutableArray so that you can add and remove items in BNREmployee.m.
        That is why you are declaring a property and an instance variable: in this case, the type of the property and the type of the instance variable are not the same.
        § To process the BNREmployee.m file, the complier needs to know a lot about the BNRAsset class. Thus, you imported BNRAssert.h instead of using @class.
        § When unnecessarily objects do not get deallocated, you are said to have a memory leak.
        Typically, a memory leak causes more and more objects to linger unnecessarily over time, which will cause your application to run low on memory.
• Class Extensions
    ○ The header file is where a class advertises its properties and methods so that other objects will know how to interact with it.
    ○ However, not every property or method should be advertised in a class's header. Some properties or methods may only be intended for use by the class or instance 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.
    ○ Typically, class extensions are added to the class implementation file above the @implementation block where methods are implemented.
    ○ A class extension starts with @interface and finishes off with @end.
    ○ Hiding mutability
    ○ Headers and inheritance
        § A subclass has no access to its superclass's class extensions. A subclass  imports its superclass's header file.
        Thus, the subclass knows about what is declared in superclass's header but knows nothing about anything that subclass may have declared in a class extension.
    ○ Headers and generated instance variables
        § When a class declares a property in its header, only the accessors for this property are visible to others.
        Non-BNREmployee objects (including subclasses) cannot directly access the instance variables generated by property declarations.
• Preventing Memory Leaks
    ○ It is pretty common to have relationships that go in two directions.
    ○ 
    From a design standpoint, you would say that you are adding a pointer from the child (an instance of BNRAsset) back to its parent (the instance of BNREmployee that is holding it)
    ○ This bring us to a style question: When people use the BNRAsset class and BNREmployee class together, how do you make sure that the two relationships are consistent? That is, an asset should appear in an employee's assets array if and only if the employee is the asset's holder.
    There are three options:
        § Set both relationships explicitly
        § In the method that sets the child's pointer, add the child to the parent's collection.
        § In the method that adds the child to the parent's collection, set the child's pointer.
    ○ In this exercise, you will take this last option. Build and run the program. 
    Notice that now none of the employees with assets are getting deallocated properly. Also, none of the assets are being deallocated, either.
    ○ Strong reference cycles
        § The asset owns the employee, the employee owns the assets array, and the assets array owns the asset.
        It is an island of garbage created by this circle of ownership. These objects should be getting deallocated to free up memory, but they are not.
        This is known as a strong reference cycle. Strong reference cycles are a very common source of memory leaks.
        § To find strong reference cycles in your program, you can use Apple's profiling tool, Instruments. When you profile a program, you monitor it while it runs to see what is happening behind the scenes with your code and the system. However, your program runs and exits very, very quickly. To give you time to profile, put in a hundred seconds of sleep() at the end of your main() function:
        (Xcode - Product -Profile - Leaks)
    ○ Weak references
        § Use a weak reference to fix a strong reference cycle.
        § 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.
    ○ Zeroing of weak references
        § 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.
        § If you are explicitly declaring a pointer variable that should be weak, mark it with __weak like this:
        __weak BNRPerson *parent;
    ○ For the More Curious: manual reference counting and ARC history
        § Before  ARC was added to Objective-C, you had manual reference counting, which used retain counts. With manual reference counting, ownership changes only happened when you sent an explicit message to an object that decremented or incremented the retain count.
        § You would see these sorts of calls primarily in accessor methods (where the new value was retained and the old value was released) and in dealloc methods (where all the previously retained objects were released)
        § ARC uses the autorelease pool automatically, but you must create and drain the pool. When ARC was created, we also got a new syntax for creating an autorelease pool. The code looks like this:
            //Create the autorelease pool
            @autoreleasepool {
                //…
            } //The pool is drained
        § Retain count rules
            □ There are a set of memory management conventions that all Objective-C programmers follow. If you are using ARC, it is following these conventions behind the scenes.
            □ In these rules, we use the word "you" to mean "an instance of whatever class you are currently working on."
                ® If you create an object using a method whose name starts with alloc or new or contains copy, then you have taken ownership of it.
                ® An object created through any other means is not owned by you.
                ® If you do not own an object and you want to ensure its continued existence, take ownership by sending it the message retain.
                ® When you own an object and no longer need it, give up ownership by sending it the message release or autorelease.
                ® As long as an object has at least one owner, it will continue to exist.
• Collection Classes
    ○ A collection class is one whose instances hold pointers to other objects.
    (NSArray / NSMutableArray / NSSet / NSMutableSet / NSDictionary / NSMutableDictionnary)
    ○ NSSet / NSMutableSet
        § A set is a collection that has no sense of order, and a particular object can only appear in a set once.
        § Sets are primarily useful for asking the question "Is it in there?"
        Sets are faster at testing object membership than arrays are.
        § Like arrays, sets come in immutable and mutable flavors: 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.
        § You cannot access an object in a set by index because there is no sense of order in a set.
        Instead, all you can do is ask "Is there one of these in there?"
            - (BOOL) containsObject: (id)x;
        § When you send this message to a set, it goes through its collection of objects looking for an object equal to x.
        The class NSObject defines a method called isEqual:
        NSObject has a simple implementation of isEqual:. It looks like this:
            - (BOOL) isEqual: (id)other
            {
                Return (self == other)
            }
        Some classes override isEqual:. For example, in NSString, isEqual: is overridden to compare the characters in the string. For these classes, there is a difference between equal and identical.

            - Foo is not equal or identical to any of others.
            - Bar and baz are equal and identical because the objects they point to have the same letters in the same order, and in fact they point to the same object.
            - Baz and bug are equal, but they are not identical.
        Thus, identical objects are always equal. Equal objects are not always identical.
        For example, NSMutableArray has two method:
            - (NSUInteger) indexOfObject: (id) anObject;
            - (NSUInteger) indexOfObjectIndenticalTo: (id) anObject;
        The first steps through the collection asking each object "isEqual: anObject?" The second steps through the collection asking each object "== anObject"?
    ○ NSDictionary / NSMutableDictionary
        § A dictionary is a collection of key-value pairs.
        The key is typically a string, and the value can be any sort of object.
        Dictionaries are indexed by key: you provide a key and get back the value (an object) associated with that particular key.
        Keys in a dictionary are unique and a dictionary's key-value pairs are not kept in any particular order.
        § Dictionaries can be mutable or immutable.
        § It has a shorthand to create an immutable dictionary. 
        The dictionary literal syntax is formed with the @symbol and curly braces. Within the curly braces, you provide a comma-delimited list of the key-value pairs and separate each key from its value with a colon.
            NSDictionary *numberOfMoons = @{ @"Mercury" : @0,
                                       @"Venus"     : @67,
                                        //… };
        The keys are NSString objects, and the values are NSNumber objects. Both are created on the spot using literal syntax.
        Here is how you would access an item from this dictionary:
            NSString *marsMoonCount = numberOfMoons[@"Mars"];
        This is similar to how you access an item in an array except, within the square brackets, you give the item's key rather than its integer index.
        § Sometimes it is useful to nest collections
            NSDictionary *innerPlanetsMoons = @{
                @"Mercury" : @[],
                @"Venus"     : @[],
                @"Earth"      : @[ @"Luna"],
                @"Mars"       :@[ @"Deimos", @"Phobos"]
            };
        § If you try to add a second object under an existing key, the first key-value pair gets replaced.
    ○ Immutable objects
        § The existing of immutable objects if for performance and security:
        You do not trust the people you work with. That is, you want to let them look at an array, but you do not want them to be able change it. A gentler approach is to give them an NSMutableArray but tell them it is an NSArray.
        § Using an immutable collection conserves memory and improves performance because that collection never needs to be copied. With a mutable object, there is the possibility that some other code might change the object behind your back while you are in the middle of using it. To avoid this situation, you would have to make a private copy of the collection. And so would everyone else, which leads to multiple copies of a potentially large object.
        § With immutable objects, making a copy is unnecessary. In fact, where the copy method of NSMutableArray makes a copy of itself and returns to the new array, the copy method of NSArray does nothing - it just quietly returns a pointer to it self.
        § Immutable objects are fairly common in Objective-C programming. In Foundation, there are many classes that create immutable instances: NSArray, NSString,NSAttributedString, NSData, NSCharacterSet, NSDictionary, NSSet, NSIndexSet, and NSURLRequset.
        All of these have mutable subclasses: NSMutableArray, NSMutableString, NSMutableAttributedString, etc.
        § NSDate and NSNumber are immutable but do not have mutable subclasses. If you need a new date or number, then you must create a new project.
    ○ Sorting arrays
        § Immutable arrays cannot be sorted, but mutable ones can. There are several ways to sort an NSMutableArray. There most common is using the NSMutableArray method:
            - (void) sortUsingDescriptors: (NSArray *) sortDescriptors; 
        § The argument is an array of NSSortDescriptor objects. A sort descriptor has the name of a property of the objects contained in the array and whether that property should be sorted in ascending or descending order.
            If you wanted to sort the list by last name in ascending (A-Z) order, then you would create the following sort descriptor:
            NSSortDescriptor *lastAsc = [NSSortDescriptor sortDescriptorWithKey: @"lastName" ascending:YES];
        The property you sort on can be any instance variable or the result of any method of the objcet.
    ○ Filtering
        § When you filter a collection, you compare its objects to a logical statement to get a resultant collection that only contains objects for which the statement is true.
        § A predicate contains a statement that might be true, like "The employeeID is greater than 75." There is a class called NSPredicate. NSMutableArray has a handy method for discarding all the objects that do not satisfy the predicate:
        -(void) filterUsingPredicate: (NSPredicate *)predicate;
        § With NSArray, you cannot remove objects that do not match the predicate. Instead, NSArray has a method that creates a new array that contains all the objects that satisfy the predicate:
        -(NSArray) filteredArrayUsingPredicate: (NSPredicate *) predicate;
        § NSSet has the method:
        -(NSSet *) filteredSetUsingPredicate: (NSPredicate *) predicate;
        -(void) filterUsingPredicate: (NSPreicate *) predicate;
    ○ Collections and ownership
        § When you add an object to a collection, the collection claims ownership of it. When you remove the object from the collection, the collection gives up ownership. This is true for NSMutableArray, NSMutableSet, and NSMutableDicitionary.
    ○ C primitives types
        § The collections covered in this chapter only hold objects. What if you want a collection of floats or ints?
        You can wrap common C number types using NSNumber.
        § You can create a literal NSNumbe instance using the @symbol.
        NSMutableArray *list = [[NSMutableArray alloc] init];
        [list addObject:@4];
        [list addObject:@5.6];
        § Note that you cannot do math directly with an NSNumber, only with primitives. You must first extract the primitive value using one of several NSNumber methods, do the math, and then re-wrap the result into an NSNumber.
        § You can wrap a pointer to a struct in an instance of another wrapper class - NSValue (the superclass of NSNumber).
        Commonly-used structs such as NSPoint  can be boxed using instances of NSValue:
            NSPoint somePoint = NSMakePoint(100,100);
            NSValue *pointValue = [NSValue valueWithPoint: somePoint];
            [list addObject:pointValue];
        NSValue instance can be used to hold just about any scalar value.
    ○ Collections and nil
        § You are not allowed to add nil to any of the collection classes we have covered.
        § There is a class called NSNull. There is exactly one instance of NSNull, and it is an object that represents nothingness.
        NSMutableArray *hotel = [[NSMutableArray alloc] init];
        [hotel addObject: [NSNull null]];
• Constants
    ○ There are two common ways that Objective-C programmers define them: #define and global variable.
    ○ Preprocessor directives
        § Compiling a file of C , C++, or Objective-C code is done in two passes. First, the preprocessor runs through the file. The output from the preprocessor then goes into the real compiler. Preprocessor directives start with #, and the three most popular are #include, #import, and #define.
        § #include and #import
            - #include and #import do essentially the same thing: request that the preprocessor read a file and add it to its output. Usually, you are including a file of declarations (a .h file), and those declarations are used by the compiler to understand the code it is compiling.
            - 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 specifying the name of the file to be imported, you can wrap the filename in quotes or angle brackets. Quotes indicate that the header is in your project directory. Angle brackets indicate that the header is in one of the standard locations that the preprocessor knows about.
            - In a project, it used to be pretty common to include a collection of headers in every file of code. This led to clutter at the beginning of your file and made complies take longer. To make life easier and compiles faster, most Xcode projects have a file that lists headers to be precompiled and included in every file. In your Constants project, this file is called Constants-Prefix.pch.
        § #define
            - #define tells the preprocessor, "Whenever you encounter A, replace it with B before the compiler sees it."
            - In the #define directive, you just separate the two parts (the token and its replacement) with whitespace.
            - #define can be used to make something like a function.
            - When you use #define to do function-like stuff instead of simply substituting a value, you are creating a macro.
        § Global variables
            - Instead of using #define, Objective-C programmers commonly use global variables to hold constant values.
            - Extern NSString * const NSLocaleCurrencyCode; (in .h file)
            The const means that this pointer will not change for the entire life of the program. The extern means "I promise this exists, but it will be defined in some other file."
            NSString * const NSLocaleCurrencyCode = @"currency";( in .m file)
        § Enum
            - Often you will need to define a set of constants.
            - Define an enumeration:
            - 
            - Developers get tired of typing enum BlenderSpeed, so they use typedef to create a shorthand for it:
            - 

            - 
            - Often you will not care what numbers the five speeds represent - only that they are different from each other.
            You can leave out the values, and the compiler will make up values for you:

            - Starting with OS X 10.8 and iOS 6, Apple introduced a new enum declaration syntax: NS_ENUM(). Here is what your enum looks like using this syntax:

            NS_ENUM() is actually a preprocessor macro that takes two arguments: a data type and a name.
            - Apple has adopted NS_ENUM() for enum declarations. The most important advantage of NS_ENUM() over the syntax is the ability to declare the integral data type that the enum will represent (short, unsigned long, etc)
            - With the old syntax, the complier would choose an appropriate date type for the enum, usually int. If your enum will only have four options whose values do not matter, you do not need four bytes to store it; one byte will represent integral numbers up to 255 just fine.
        § #define vs. global variables
            - In some cases, there are performance advantages to using global variables. 
            For example, you can use == instead of isEqual: to compare strings if you consistently use the global variable (a pointer comparison is faster than a message send and scanning two strings character-by-character).
            - In general, you should use global variables and enum for constants, not #define.
• Writing Files with NSString and NSData
    The Foundation Framework gives the developer a few easy ways to read from and write to files.
    ○ Writing an NSString to a file
        § When you write a string to a file, you need to specify which string encoding you are using. A string encoding describes how each character is sorted as an array of bytes. ASCII is a string encoding that defines the letter 'A' as being stored as 01000001. In UTF-16, the letter 'A' is stored as 0000000001000001.
        § The Foundation framework supports about 20 different string encodings, but we end up using UTF a lot because it can handle an incredible collection of writing systems. It comes in two flavors: UTF-16, which uses two or more bytes for every character, and UTF-8, which uses one byte for the first 128 ASCII characters and two or more for other characters. For most purposes, UTF-8 is a good fit.
    ○ NSError
        § All sorts of things can go wrong when you try to write a string to a file. For situations like these, where an operation may be impossible to complete, the method needs a way to return a description of what went wrong in addition to the boolean value for success or failure.
        § Recall from Chapter 10 that when you need a function to return something in addition to its return value, you can use pass-by-reference. You pass the function (or method) a reference to a variable where it can directly store or manipulate a value. The reference is the memory address for that variable.
        § For error handling, many methods take an NSError pointer by reference.
        § Notice that you declare a pointer to an instance of NSError in this code, but you do not create, or instantiate, an NSError object to assign to that pointer. Why not? You want to avoid creating an unnecessary error object if there is no error. If there is an error, writeToFile: atomically: encoding:error will be responsible for creating a new NSError instance and then modifying the error pointer you declared to point to the new error object. Then you can ask that object what went wrong via your error pointer.
        § This conditional creation of the NSError requires you to pass a reference to error (&error) because there is no object yet to pass. However, unlike the passing by reference you did Chap 10, where you passed the reference of a primitive C variable, here you are passing the address of a pointer value. In essence, you are passing the address of another address (which may become the address of an NSError object).
        § Methods that pass an NSError by reference always return a value that indicates whether there was an error or not. This method, for example, returns NO if there is an error. Do not try to access the NSError unless the return value indicates that an error occurred; if the NSError object does not actually exist, trying to access it will crash your program.
    ○ Reading files with NSString
    ○ Writing an NSData object to a file
        § An NSData object represents a buffer of bytes.
    ○ Reading an NSData from a file
    ○ Finding special directories
        § To make it easy for programmer to save expect files to specific directories, Apple has created a function that will tell you the right directories for the appropriate purpose.
• Callbacks
    ○ In this chapter, you are going to create a program that does not just start, execute, and end. Instead, this program is event-driven. It will start and wait for an event. What that event happens, the program will execute code in response. This program will not end by itself; it will keep sitting and waiting for the next event until you tell it to stop.
    ○ A callback lets you write to 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 just a chunk of code to be executed. Before the wait begins, you say "Here is an block. When this event happens, execute this block.
    ○ The run loop
        § In an event-driven program, there needs to be an object that does the sitting and waiting for events. In OS X and iOS, this object is an instance of NSRunLoop. We say that when an event happens, the run loop causes a callback to occur.
    ○ Target-Action
        § Timers use a target-action mechanism. You create a timer with a time interval, a target, and an action. After the interval has elapsed, the timer sends the action message to its target.
        § Timers are simple. They only do one thing: fire. Thus, target-action is a good fit. A lot of simple user interface controls, like buttons and sliders, use the target-action 
        § 
    ○ Helper objects
        § There are two problems with a synchronous connection:
            - It blocks the main thread while waiting for all the data to arrive. If you use this type of connection in an interaction application, the user interface will be unresponsive while the data was fetched.
            - It has no way to call back if, for example, the web server asks for a username and password.
        § For these reasons, it is more common to use an NSURLConnection asynchronously. In an asynchronous connection, the data comes in chunks rather than all at once. This means that there are connection-related events that you must be ready to respond to. Some examples of connection-related events are a chunk of data arrives, the web server demands credentials, and the connection fails.
        § To manage this more complex connection, you must give it a helper object. In the helper object, you implement the methods to be executed in response to different connection-related events.
        § A protocol is a list of method declarations. Learn more about protocols in Chapter 29, but for now, think of a protocol as a prearranged set of messages that an object can send its helper object.
        (Developer documentation) Protocols have references, similar to class references, with information about their methods.
        § Here are the rules, so far, for callbacks: 
            - When sending one callback to one object, Apple uses target-action. 
            - When sending an assortment for callbacks to one object, Apple uses a helper object with a protocol. These helper objects are typically called delegates or data sources.
    ○ Notifications
        § Imagine the user changes the time zone on a Mac. Many objects in your program might want to know that this event has stopped. Each of them can register as an observer with the notification center. When the time zone is changed, the notification NSSystemTimeZoneDidChangeNotification will be posted to the center, and the center will forward it to all the relevant observers.
        § Many of the classes that Apple has written post notifications when interesting things happen. You can find out what notifications a class posts in its reference in the developer documentation.
        § When you register as an observer with the notification center, you can specify the name of the notification and which posters of this notification you care about. For either of these parameters, you can supply nil, which works as the wild card. If you supply for both, you will receive every notification posted by every object in your program.
    ○ Which to use?
        § Object do just one thing (like NSTimer) use target-action.
        § Object that has more complicated lives (like an NSURLConnection) use helper objects, and the most common type of helper object is the delegate.
        § Object that might need to trigger callbacks in several other objects (like NSTimeZone) use notifications.
    ○ Callbacks and object ownership
        § Inherent in any of these callback schemes is the risk of strong reference cycles. Often the object you create has a pointer to the object that is going to call back. And it has a pointer to the object you created. If they each have strong references to each other, you end up with a strong reference cycle - neither of them will ever get deallocated.
        § Thus it was decided that:
            - Notification centers do not own their observers. If an object is an observer, it will typically remove itself from the notification center in its dealloc method:
            -(void)dealloc{
                [[NSNotificationCenter defaultCenter] removeObserver:self];
            }
            - Objects do not own their delegates or data sources. If you create an object that is a delegate or data source, your object should "excuse" itself in its dealloc method.
            -(void)dealloc{
                [windowThatBossesMeArround setDelegate:nil];
                [tableViewThatBegsForData setDataSource:nil];
            }
            - Objects do not own their targets. If you create an object that is a target, your object should zero the target pointer in its dealloc method:
            -(void)dealloc{
                [buttonThatKeepsSendingMeMessags setTarget:nil];
            }
        § How selector work
            - When you send a message to an object, the object's class is asked if it has a method with that name. The search goes up the inheritance hierarchy until a class responds with "Yeah, I have a method with that name."


            - As you can image, this search needs to happen very, very quickly. If the compiler used the actual name of the method (which could be very long ), method lookup would be really slow. To speed things up, the compiler assigns a unique number to each method name it encounters. At runtime, it uses that number instead of the method name.

            - Thus, a selector is the unique number that represents a particular method name. When a method expects a selector as an argument, it is expecting this number. You use the @selector compiler directive to tell the compiler to look up the selector for the given method name.
• Blocks
    ○ A block is a chunk of code. Here is a block:
    ^{
        NSLog(@"This is an instruction within a block.");
    }
    ○ It looks like a C function; it is a set of instructions inside curly braces. It does not, however, have a name. Instead, the caret ( ^ ) identifies this bit of code as a block.
    Like a function, a block can take arguments and return values. Here is another block:
    ^(double dividend, double divisor) {
        Double quotient = dividend / divisor;
        Return quotient;
    }
    This block takes two doubles as arguments and returns a double.
    ○ 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 argument.
    For instance, NSArray, NSDictionary, and NSSet allow block-based enumeration: Each class has at least one method that accepts a block. When one of these methods is called, it will execute the code within the passed-in block once for each object in the collection.
    ○ Using blocks
        § Declaring a block variable
        A block can be stored in a variable.

        § Composing a block
            - Now you need to compose a block of the declared type and assign it to the new variable.
            - Notice that the block assignment ends with a semi-colon just like any variable assignment would.
            - As with any variable, you can perform the declaration and assignment of the blockin one or two steps.
        § Passing in a block
        § Typedef
            - Block syntax can be confusing, but you can make it clearer using the typedef keyword.
            - Here you are defining a type rather than a variable, hence the appropriate type name next to the caret.
            This allows you to simplify declarations of similar blocks
            - Note the the block type itself only defines the block's arguments and return types; it has no bearing on the set of instructions within a block of that type.
        § Block vs. other callbacks
            - Callbacks allow other objects to call methods in your object in response to events. While perfectly functional, these approaches break up your code. Pieces of your  program that you would like to be close together for clarity's sake usually are not.
            - Blocks, on the other hand, keep the code to be triggered by an event close by.
        § More on blocks
            - Return value
            When a block returns a value, you can get the return value by calling the block variable like a function.
            - Anonymous blocks
            An anonymous block is a block that you pass directly to a method without assigning it to a block variable first.
            - External variables
            A block typically uses other variables that were created outside of the block. These are called external variables. To make sure that they will be available for as long as the block needs them, these variables are captured by the block.
            For primitive variables, the values are copied and stored as local variables within the block. For pointers, the block will keep a strong reference to the objects it references. This means that any objects referred to by the block are guaranteed to live as long as the block itself.
            - Using self in blocks
                ® If you need to write a block that uses self, you must take a couple of extra steps to avoid a strong reference cycle.
                ® To break the strong reference cycle, you declare a __weak pointer outside the block that points to self. Then you can use this pointer inside the block instead of self.
                ® However, because the reference is weak, the object that self points to could be deallocated while the block is executing.
                You can eliminate this risk by creating a strong local reference to self inside the block.
                ® By creating the strong innerSelf reference, you have again created a strong reference cycle between the block and the BNREmployee instance. But because the innerSelf reference is local to the scope of the block, the strong reference cycle will only exist while the block is executing and will be broken automatically when the block ends.
            - Unexpectedly using self in blocks
                ® If you use an instance variable directly within a block, the block will capture self instead of the instance variable. This is because of a little-known nuance of instance variables.
                ® Don't access instance variables directly. Use your accessors!
                ® However, you should never use the -> syntax to access an object's instance variables in your code.
                Accesors are your friends, and you should use them.
            - Modifying external variables
                ® By default, variables captured by a block are constant within the block, and you cannot change their values. If you want to be able to modify an external variable within a block, you must declare the external variable using the __block keyword.
• Protocols
    ○ The class of an object is different from its role in a working system. 
    For example, an object may be an instance of NSMutableArray, but its role in an application may be as a queue of print jobs to be run.
    ○ A protocol can specify a role that an object can fill. (Protocols are called "interfaces" in Java)
    ○ A protocol is a list of method declarations. Some of these methods are required, and some are optional. If an object is to fill the specified role, then it must implement the required methods. It may choose an implement one or more of the optional methods.
    ○ The developer who created the UITableView class specified the role of UITableView's data source by creating the UITableViewDataSource protocol.
    ○ Like classes, protocols that Apple provides have reference pages in the developer documentation. You can browse a protocol's reference to see the methods that it contains.
    The compiler considers an object to have successfully conformed to a protocol if the object has implemented all of the protocol's required methods.
    When you create a class to fill the role of UITableView's data source, you explicitly say, "This class conforms to the UITableView DataSource protocol" in the header file. It looks like this:

    This is,  "TerrificViewController is a subclass of UIViewController and conforms to the UITableViewDataSource protocol."
    If your class conforms to several protocols, you list them within the angle brackets:

    Then, in the TerrificViewController.m file, you must implement the required methods. If you forget to implement one of the required methods, you will get a stern warning from the compiler.
    ○ Calling optional methods
        § If you send a message to an object and that method is not implemented by the object's class, then the program will crash.
        How, then, do optional methods in protocols work?

• Property Lists
    ○ Sometimes you need a file format that can be read by both computers and people.
    ○ A property list is a combination of any of the following things:
        § NSArray
        § NSDictionary
        § NSString
        § NSData
        § NSDate
        § NSNumber ( integer, float, or Boolean )
    ○ For example, an array of dictionaries with string keys and date objects is a property list.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Android编程:The Big Nerd Ranch指南(第5版)》是一本针对Android编程的权威指南。这本书由Phillips、Stewart和Marsicano三位经验丰富的作者撰写,并由Big Nerd Ranch出版,对于想要学习和掌握Android编程的读者来说是一本必备的参考书。 这本书的第5版是一本全面更新和改进的指南,以帮助读者掌握最新的Android编程技术。它深入介绍了Android的核心概念和最佳实践,从而帮助读者全面了解Android应用的开发过程。 这本书以互动式的方式逐步引导读者进行Android应用开发,从创建一个简单的"Hello World"应用开始,逐渐深入介绍不同方面的开发技术,包括界面设计、数据存储和管理、网络通信、多媒体和设备功能等。 它采用了清晰明了的语言和丰富的示例代码,帮助读者理解和实践各种概念和技术。此外,这本书还通过挑战性练习和应用案例来培养读者的实际编程能力和解决问题的能力。 该书还引入了与现代开发实践相关的最新主题,例如响应式编程、单元测试和持续集成等。这些主题使读者能够更好地开发和维护高质量的Android应用。 总的来说,《Android编程:The Big Nerd Ranch指南(第5版)》是一本重要的Android编程指南,对于想要学习和应用这一技术的读者来说具有很高的实用价值。无论是初学者还是有经验的开发者,都可以通过这本书提供的深入理论和实践指导,加强他们的Android编程技能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值