版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2017.08.31 |
前言
NSString
、NSArray
和NSDictionary
是大家一定會(huì)用到的類贷祈,但是大家有沒有發(fā)現(xiàn)趋急,除了系統(tǒng)的三個(gè)子類NSMutableArray
、NSMutableString
和NSMutableDictionary
繼承自它們幾個(gè)势誊,你見過自定義的類繼承它們的嗎呜达?下面我們就深入探討這個(gè)問題。
問題提出
就我目前做的這些項(xiàng)目而言粟耻,說實(shí)話我沒見過誰自定義類繼承NSString
查近、NSArray
和NSDictionary
,是因?yàn)橥耆珱]有這個(gè)功能要求上的必要自定義類繼承自它們挤忙,還是因?yàn)樘O果原則上就不允許我們自定義繼承它們的類呢嗦嗡?
下面我們就研究一下。
問題分析
下面我們還是先看代碼饭玲,自定義一個(gè)類繼承自NSString
,如下所示叁执。
1. JJString.h
#import <Foundation/Foundation.h>
@interface JJString : NSString
@end
2. JJTestStringVC.h
#import <UIKit/UIKit.h>
@interface JJTestStringVC : UIViewController
@end
3. JJTestStringVC.m
#import "JJTestStringVC.h"
#import "JJString.h"
@interface JJTestStringVC ()
@end
@implementation JJTestStringVC
- (void)viewDidLoad
{
[super viewDidLoad];
JJString *str = [JJString stringWithString:@"ABC"];
NSLog(@"%@", str);
}
@end
運(yùn)行就發(fā)現(xiàn)奔潰了茄厘,輸出信息如下所示:
2017-08-31 19:06:37.081 JJOC[1374:34198] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** initialization method -initWithCharactersNoCopy:length:freeWhenDone: cannot be sent to an abstract object of class JJString: Create a concrete instance!'
*** First throw call stack:
(
0 CoreFoundation 0x000000010d8b4b0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010cf3b141 objc_exception_throw + 48
2 CoreFoundation 0x000000010d91d625 +[NSException raise:format:] + 197
3 Foundation 0x000000010cb45730 -[NSString initWithCharactersNoCopy:length:freeWhenDone:] + 14
4 Foundation 0x000000010ca49869 +[NSString stringWithString:] + 45
5 JJOC 0x000000010c75a3fe -[JJTestStringVC viewDidLoad] + 94
6 UIKit 0x000000010f30f01a -[UIViewController loadViewIfRequired] + 1235
7 UIKit 0x000000010f34de6c -[UINavigationController _layoutViewController:] + 56
8 UIKit 0x000000010f34e74a -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 466
9 UIKit 0x000000010f34e8bb -[UINavigationController _startTransition:fromViewController:toViewController:] + 127
10 UIKit 0x000000010f34fa03 -[UINavigationController _startDeferredTransitionIfNeeded:] + 843
11 UIKit 0x000000010f350b41 -[UINavigationController __viewWillLayoutSubviews] + 58
12 UIKit 0x000000010f54260c -[UILayoutContainerView layoutSubviews] + 231
13 UIKit 0x000000010f22f55b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268
14 QuartzCore 0x000000010edae904 -[CALayer layoutSublayers] + 146
15 QuartzCore 0x000000010eda2526 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 370
16 QuartzCore 0x000000010eda23a0 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
17 QuartzCore 0x000000010ed31e92 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
18 QuartzCore 0x000000010ed5e130 _ZN2CA11Transaction6commitEv + 468
19 QuartzCore 0x000000010ed5eb37 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 115
20 CoreFoundation 0x000000010d85a717 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
21 CoreFoundation 0x000000010d85a687 __CFRunLoopDoObservers + 391
22 CoreFoundation 0x000000010d83f038 CFRunLoopRunSpecific + 440
23 UIKit 0x000000010f16608f -[UIApplication _run] + 468
24 UIKit 0x000000010f16c134 UIApplicationMain + 159
25 JJOC 0x000000010c75a37f main + 111
26 libdyld.dylib 0x0000000111b3a65d start + 1
27 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
從上面我們可以看見:
- 方法
NSString stringWithString:
調(diào)用后矮冬,會(huì)調(diào)用NSString initWithCharactersNoCopy:length:freeWhenDone:
。然后就接著調(diào)用NSException raise:format:
次哈,接著就會(huì)拋出異常胎署。
這里需要理解一下:這里就是類簇的問題,類簇就是把一組有共同特性的子類都繼承說一個(gè)父類窑滞,當(dāng)我們?cè)谛枰鱾€(gè)子類的時(shí)候琼牧,我們就需要去操作父類就可以,運(yùn)用抽象工廠模式哀卫,父類會(huì)根據(jù)你的需求返回給你相應(yīng)的子類巨坊。
下面我們?cè)诳匆幌吕?/p>
#import "JJTestStringVC.h"
#import "JJString.h"
@interface JJTestStringVC ()
@end
@implementation JJTestStringVC
- (void)viewDidLoad
{
[super viewDidLoad];
id obj1 = [NSString alloc];
id obj2 = [NSMutableString alloc];
id obj3 = [obj1 init];
id obj4 = [obj2 init];
id obj5 = [JJString alloc];
id obj6 = [obj5 init];
NSLog(@"obj1 = %@", [obj1 class]);
NSLog(@"obj2 = %@", [obj2 class]);
NSLog(@"obj3 = %@", [obj3 class]);
NSLog(@"obj4 = %@", [obj4 class]);
NSLog(@"obj5 = %@", [obj5 class]);
NSLog(@"obj6 = %@", [obj6 class]);
}
@end
下面看輸出結(jié)果
2017-08-31 20:34:54.585 JJOC[2358:75128] obj1 = NSPlaceholderString
2017-08-31 20:34:54.585 JJOC[2358:75128] obj2 = NSPlaceholderMutableString
2017-08-31 20:34:54.585 JJOC[2358:75128] obj3 = __NSCFConstantString
2017-08-31 20:34:54.586 JJOC[2358:75128] obj4 = __NSCFString
2017-08-31 20:34:54.586 JJOC[2358:75128] obj5 = JJString
2017-08-31 20:34:54.586 JJOC[2358:75128] obj6 = JJString
這里大家可以看到:
-
NSString
和NSMutableString
調(diào)用alloc
的時(shí)候會(huì)生成一個(gè)對(duì)象NSPlaceholderString
。 -
NSString
調(diào)用init
的時(shí)候會(huì)生成對(duì)象__NSCFConstantString
此改,而NSMutableString
調(diào)用init
的時(shí)候會(huì)生成對(duì)象__NSCFString
趾撵。 -
JJString
調(diào)用alloc
和init
的時(shí)候還是JJString
對(duì)象。
為什么會(huì)是這個(gè)樣子共啃,其實(shí)可以從下面幾個(gè)情況著手:
- 這里占调,
NSPlaceholderString
是一個(gè)中間對(duì)象。后面的-init
或- initWithXXXXX
消息都是發(fā)送給這個(gè)中間對(duì)象移剪,再由它做工廠究珊,生成真的對(duì)象分別是這里的NSCFConstantString
和NSCFString
類。
那么為什么我們自己的類調(diào)用alloc時(shí)纵苛,就不返回NSPlaceholderString
這個(gè)類對(duì)象了呢剿涮?關(guān)鍵就在于NSString alloc方法的實(shí)現(xiàn)。NSString的alloc方法實(shí)現(xiàn)可以猜測(cè)一下:
@class NSPlaceholderString;
@interface NSString:(NSObject)
+ (id) alloc;
@ end
@implementation NSString
+(id) alloc
{
if ([self isEquals:[NSString class]]) {
return [NSPlaceholderString alloc];
}
else
return [super alloc];
}
@end
@interface NSPlaceholderString:(NSString)
@end
關(guān)鍵就在于alloc的實(shí)現(xiàn)赶站,可以發(fā)現(xiàn)幔虏,當(dāng)只用NSString調(diào)用alloc的時(shí)候,由于self == [NSString class]
贝椿,所以這時(shí)返回的是NSPlaceholderString
的類對(duì)象想括;而使用其他類(比如派生類)調(diào)用alloc時(shí),返回的是super的 alloc烙博,這里也就是[NSObject alloc]
瑟蜈,而NSObject的alloc方法返回的是調(diào)用類的類對(duì)象,所以在我們用我們自己的LBString就是LBString類的類對(duì)象了所以沒有NSString 的一些方法了渣窜。
參考文章
1. Foundation庫下的NSString,NSArray, NSDictionary……可以被繼承嗎
后記
感謝這個(gè)技術(shù)大牛給的技術(shù)指導(dǎo)铺根,致敬,引用參考已經(jīng)列到參考文章里面了乔宿。謝謝大家位迂,希望對(duì)大家有所幫助。