IOS4 note 11 (Chapter 10)

Subclassing

Often, the default behavior or appearance of an object supplied by Cocoa won’t be quite what you’re after, and you’ll want to customize it.Nevertheless, sometimes setting properties and calling methods won’t suffice to customize an instance the way you want to. In such cases, Cocoa may provide methods that are called  internally as an  instance does  its  thing, and whose behavior you can customize by subclassing and overriding. You don’t have the code to any of Cocoa’s built-in classes, but you can still subclass them, creating a new class that acts just like a built-in class except for the modifications you provide.

A  common  case  involves  custom drawing  into  a UIView. You don’t  actually draw

into a UIView; rather, when a UIView needs drawing, its drawRect: method is called so that  the view can draw  itself. So  the way  to make a UIView  that  is drawn  in  some completely custom manner is to subclass UIView and implement drawRect: in the subclass. As the documentation says, “Subclasses override this method if they actually draw their views.” That’s a pretty strong hint that you need to subclass UIView in order to do custom drawing into a UIView.

For example, suppose we want our window to contain a horizontal line. There is no horizontal  line  interface widget, so we’ll  just have to roll our own — a UIView that draws itself as a horizontal line. Let’s try it. First we’ll code the class:

1. In our Empty Window example project, choose File → New → New File and specify a Cocoa Touch Objective-C class, and in particular a subclass of UIView. Call it MyHorizLine. Xcode creates MyHorizLine.m and MyHorizLine.h.

2. In MyHorizLine.m,  remove  the comment delimiters  from around  the drawRect: implementation, and make  it  look  like  this:

- (void)drawRect:(CGRect)rect {

    CGContextRef c = UIGraphicsGetCurrentContext();

    CGContextMoveToPoint(c, 0, 0);

    CGContextAddLineToPoint(c, self.bounds.size.width, 0);

    CGContextStrokePath(c);

}

3. Edit MainWindow.xib. Show the Window top-level object in the canvas. Find UIView in the Object library, and drag it into the Window object in the canvas.

4. Select the UIView in the window and use the Identity inspector to change its class to MyHorizLine.

 

You wouldn’t  subclass UIApplication  (the  class of  the  singleton  shared application instance) just in order to respond when the application has finished launching, because the delegate mechanism (Chapter 11) provides a way to do that (application:didFinishLaunchingWithOptions:). On the other hand, if you need to perform certain tricky customizations of your app’s fundamental event messaging behavior, you’d have to subclass UIApplication in order to override sendEvent:. The documentation does tell you this, and it also tells you, rightly, that needing to do this would be fairly rare (though I have had occasion to do it).

If you do subclass UIApplication, you’ll need to change the third argument in the call to UIApplicationMain in main.m from nil to the NSString name of your subclass. Otherwise your UIApplication subclass won’t be instantiated as the shared application instance.

 

 

Categories

A category  is an Objective-C  language feature that allows you to reach right  into an existing class and define additional methods. You can do this even if you don’t have the code  for  the class, as with Cocoa’s classes. Your  instance methods can  refer  to self, and this will mean the instance to which the message was originally sent, as usual.

A category, unlike a subclass, cannot define additional instance variables; it can override methods, but you should probably not take advantage of this ability. 

For example, in one of my apps I found myself performing a bunch of string transformations in order to derive the path to various resource files inside the app bundle based on  the resource’s name and purpose.  I ended up with half a dozen utility methods. Given that these methods all operated on an NSString, it was appropriate to implement them as a category of NSString, thus allowing any NSString, anywhere in my code, to respond to them.

The code was structured like this (I’ll show just one of the methods):

// [StringCategories.h]

#import <Foundation/Foundation.h>

@interface NSString (MyStringCategories)

- (NSString*) basePictureName;

@end

// [StringCategories.m]

#import "StringCategories.h"

@implementation NSString (MyStringCategories)

- (NSString*) basePictureName {

    return [self stringByAppendingString:@"IO"];

}

@end

 

A category is particularly appropriate in the case of a class like NSString, because the documentation  warns  us  that  subclassing  NSString  is  a  bad  idea.  That’s  because NSString  is part of a complex of classes called a  class  cluster, which means  that an NSString object’s real class might actually be some other class. A category is a much better way to modify a class within a class cluster than subclassing.

Cocoa itself takes does this. A good example is NSString. NSString is defined as part
of the Foundation framework, and its basic methods are declared in NSString.h. Here we  find  that NSString  itself, with  no  category,  has  just  two methods,  length and characterAtIndex:, because these are regarded as the minimum that a string needs to do in order to be a string. Additional methods — those that create a string — deal with a string’s encoding,  split a  string,  search  in a string, and  so on, are clumped  into a category. A  string also may  serve as a  file pathname,  so we also  find a category on NSString  in NSPathUtilities.h, where methods are declared  for splitting a pathname string into its constituents and the like. Then, in NSURL.h, there’s another NSString
category, declaring a couple of methods for dealing with percent-escaping  in a URL string. Finally, off in a completely different framework (UIKit), UIStringDrawing.h adds yet another NSString category, with methods for drawing a string in a graphical context.
This organization won’t matter  to you as a programmer, because an NSString  is an NSString, no matter how it acquires its methods, but it can matter when you consult the documentation. The NSString methods declared in NSString.h, NSPathUtilities.h, and NSURL.h  are  documented  in  the NSString  class  documentation  page,  but  the NSString methods declared  in UIStringDrawing.h are not, presumably because  they originate  in  a  different  framework.  Instead,  they  appear  in  a  separate  document, NSString UIKit Additions Reference. As a  result,  the string drawing methods can be difficult to discover, especially as the NSString class documentation doesn’t link to the other document (although it does mention it). I regard this as a flaw in the structure of the Cocoa documentation. A third-party utility such as AppKiDo can be helpful here.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值