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

    • Init
      • 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. This chapter is about how to write initializers.
      • Writing init methods
      • A basic init method
        • Instancetype
          • The instancetype keyword tells the compiler to expect an instance of the class to which a method belongs. Any initializers you write or override should always return instancetype.
          • Sometimes you will see initializers returning id. Before Xcode 4.3 (when instancetype was introduced), developers return id from initializers. Recall that id means "any object", so id also provides flexibility for subclassing when writing your own initializers. However, instancetype is the better option. It provides flexibility but still lets the compiler check the type of what is returned against the rest of your code.
        • Using and checking the superclass initializer
          • Your init method begins with two checks:
            • 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.
          • What do these checks do? A few classes have deviant init methods. There are two possible forms of deviance:
            • The init method figures out a clever optimization that it can do, deallocates the original object, allocates a different object, and return 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.

    • Init methods that take arguments
      •  Sometimes an object cannot be initialized properly without some information from the method that is calling it.
      • You cannot do this with init because, for now and always, init has no arguments. So you have to create a new initializer instead.
      • Using accessors
        • When typically do a plain assignments in an initializer, but many programmers will use the accessors methods.
        • At Big Nerd Ranch, we tend to set the instance variables directly and we typically do this assignment and check the superclass's initializer in one line.
      • Multiple initializers
        • 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.
        • When you create a class whose designated initializer has a different name than its superclass's designated initializer, you have a responsibility to document that in the header file.
        • The rules that all stylish Objective-C programmers follow when writing initializers:
          • If a class has several initializers, only one should do the real work. That method is known as the designated initializer. All other initializer 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.
      • Deadly init method
        • Every once in a while, however, you cannot safely override the superclass's designated initializer.
        • The best thing to do is to override the superclass's designated initializer in a way that lets developer know that they have made a mistake and tells them how to fix:
          • Throwing an exception like this will crash the program. In the console output, developers will see their mistake that led to the crash.
    • More about Properties
      • More on property attributes

    First let's take a closer look at the different attributes you can use to control how the accessors will be created.

    • Mutability

    A property can be declared readwirte 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:

    @property (readonly) int voltage;

    • Lifetime specifiers

    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 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. This is a neat feature that keeps you safe from dangling pointer. A dangling pointer point 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 is points to is deallocated.
    • Copy forms a strong reference to a copy of the passed-in object. But there is a detail in this that most people misunderstand…

    The copy option makes a copy of an object and then changes the pointer to refer to this copy. Imagine you had a property declaration and definition like this:

    @property (copy) NSString *lastName;

    The generated setter method would look pretty much like this:

    -(void) setLastName: (NSString *)d{

    _lastName = [d  copy];

    }

    Use of the copy attribute is most common with object types that have mutable subclasses. For example, NSString has a subclass called NSMutableString. You can imagine that your setLastName: method might be passed a mutable string:

    NSMutableString *x = [[NSMutableString alloc] initWithString:@"One"];

    [myObj setLastName:x];

    [x appendString:@" Lennon"];

    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. That is, it does not make a copy at all.

    For objects that come in mutable and immutable versions, the copy method returns an immutable copy. If you want the copy to be a mutable object, use the mutablecopy method.

    There is no property lifetime specifier called mutableCopy. If you wish for you setter to set the property to be a mutable copy of an object, you must implement the setter yourself so that it calls the mutableCopy on the incoming object.

    Many of the classes in the Foundation framework conform to one or both of these protocols. If you want your classes to be compatible with the copy property lifetime specifier, then you must ensure that they conform to the NSCopying protocol.

    • Advice on atomic vs. nonatomic
      • The atomic/nonatomic option relates to a relatively advanced topic known as multithreading. The nonatomic option will make your setter method run a tiny bit faster. If you look at the headers for Apple's UIKit, every property is marked as nonatomic. You should always make your readwrite properties nonatomic, too.
    • Implementing accessor methods
      • By default, the compiler synthesizes accessor methods for any property you declare. Usually, accessor method implementation are straightforward and thus well-suited to be handed off to the compiler.
      • 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.

    If you still want an instance variable, you must create it yourself by adding an @synthesize statement to the class's implementation.

    • When you declare a readonly property, the complier automatically synthesizes only a getter method and an instance variable. Thus, if you implement the getter method for a readonly property yourself, the effect is the same as implementing both accessors for a readwrite property. The complier will not synthesize an instance variable, and you will need to synthesize it yourself.
    • Key-Value coding
      • 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.
      • Why is key-value coding interesting? Anytime a standard framework wants to push data into your objects, it will use setValue:forKey:. Anytime a standard framework wants to read data from your objects, it will use valueForKey:.
      • Non-object types
        • The key-value coding methods are designed to work with objects, but some properties hold a non-object type, like an int or a float. For example, voltage is an int. How do you set voltage using key-value coding? You use an NSNumber.
      • Key paths
        • Most applications end up with a relatively complex object graph.
        • Using a key path, you can make the system traverse the relationships for you. Put the keys that you want followed in one long string separated by dots. The order is important; the first relationship you want traversed comes first.

    You can also set the property at the end of a key path.

    • Key-Value Observing
      • Key-value observing is a technique that lets you get a notification when a particular property of an object changes. Although you will not use it everyday, KVO is a crucial part of what makes Cocoa bindings and Core Data possible.
      • 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.
      • Using the context in KVO
        • Notice that when you register as an observer, you can pass a pointer to anything as context. When you are notified of the change, you will receive that same pointer with the notification. The most common use of this is to answer "Is this really the notification that I asked for?"
      • Triggering the notification explicitly
        • The system can automatically inform the observer if you use the accessor method to set the property. What if you, for some reason, choose not to use the accessor? You can explicitly let the system know that you are changing a property.
    • Categories
      • Categories let a programmer add methods to any existing class. For example, Apple gave us the class String. Apple does not share the source code to that class, but you can use a category to add new method to it.
      • You should use categories to add functionality to existing classes. Do not use them to replace functionality in existing classes; use subclassing instead.

     


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Title: Android Programming: The Big Nerd Ranch Guide, 3rd Edition Author: Bill Phillips, Chris Stewart Length: 624 pages Edition: 3 Language: English Publisher: Big Nerd Ranch Guides Publication Date: 2017-02-09 ISBN-10: 0134706056 ISBN-13: 9780134706054 Table of Contents Chapter 1. Your First Android Application Chapter 2. Android and Model-View-Controller Chapter 3. The Activity Lifecycle Chapter 4. Debugging Android Apps Chapter 5. Your Second Activity Chapter 6. Android SDK Versions and Compatibility Chapter 7. UI Fragments and the Fragment Manager Chapter 8. Displaying Lists with RecyclerView Chapter 9. Creating User Interfaces with Layouts and Widgets Chapter 10. Using Fragment Arguments Chapter 11. Using ViewPager Chapter 12. Dialogs Chapter 13. The Toolbar Chapter 14. SQLite Databases Chapter 15. Implicit Intents Chapter 16. Taking Pictures with Intents Chapter 17. Two-Pane Master-Detail Interfaces Chapter 18. Localization Chapter 19. Accessibility Chapter 20. Data Binding and MVVM Chapter 21. Unit Testing and Audio Playback Chapter 22. Styles and Themes Chapter 23. XML Drawables Chapter 24. More About Intents and Tasks Chapter 25. HTTP and Background Tasks Chapter 26. Loopers, Handlers, and HandlerThread Chapter 27. Search Chapter 28. Background Services Chapter 29. Broadcast Intents Chapter 30. Browsing the Web and WebView Chapter 31. Custom Views and Touch Events Chapter 32. Property Animation Chapter 33. Locations and Play Services Chapter 34. Maps Chapter 35. Material Design Chapter 36. Afterword

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值