欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

不可錯(cuò)過的iOS開發(fā)技巧有哪些

這篇文章主要介紹了不可錯(cuò)過的iOS開發(fā)技巧有哪些,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)民豐免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千余家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

主要記錄了以下幾個(gè)問題:

NSString屬性什么時(shí)候用copy,什么時(shí)候用strong?

Foundation中的斷言處理

IBOutletCollection

NSRecursiveLock遞歸鎖的使用

NSHashTable

NSString屬性什么時(shí)候用copy,什么時(shí)候用strong?

我們在聲明一個(gè)NSString屬性時(shí),對于其內(nèi)存相關(guān)特性,通常有兩種選擇(基于ARC環(huán)境):strong與copy。那這兩者有什么區(qū)別呢?什么時(shí)候該用strong,什么時(shí)候該用copy呢?讓我們先來看個(gè)例子。

示例

我們定義一個(gè)類,并為其聲明兩個(gè)字符串屬性,如下所示:

  1. @interface TestStringClass () 

  2.  

  3. @property (nonatomic, strong) NSString *strongString; 

  4. @property (nonatomic, copy) NSString *copyedString; 

  5.  

  6. @end

上面的代碼聲明了兩個(gè)字符串屬性,其中一個(gè)內(nèi)存特性是strong,一個(gè)是copy。下面我們來看看它們的區(qū)別。

首先,我們用一個(gè)不可變字符串來為這兩個(gè)屬性賦值,

  1. - (void)test { 

  2.  

  3. NSString *string = [NSString stringWithFormat:@"abc"]; 

  4. self.strongString = string; 

  5. self.copyedString = string; 

  6.  

  7. NSLog(@"origin string: %p, %p", string, &string); 

  8. NSLog(@"strong string: %p, %p", _strongString, &_strongString); 

  9. NSLog(@"copy string: %p, %p", _copyedString, &_copyedString); 

  10. }

其輸出結(jié)果是:

origin string: 0x7fe441592e20, 0x7fff57519a48 strong string: 0x7fe441592e20, 0x7fe44159e1f8 copy string: 0x7fe441592e20, 0x7fe44159e200

我們要以看到,這種情況下,不管是strong還是copy屬性的對象,其指向的地址都是同一個(gè),即為string指向的地址。如果我們換作MRC環(huán)境,打印string的引用計(jì)數(shù)的話,會看到其引用計(jì)數(shù)值是3,即strong操作和copy操作都使原字符串對象的引用計(jì)數(shù)值加了1。

接下來,我們把string由不可變改為可變對象,看看會是什么結(jié)果。即將下面這一句

NSString *string = [NSString stringWithFormat:@"abc"];

改成:

NSMutableString *string = [NSMutableString stringWithFormat:@"abc"];

其輸出結(jié)果是:

origin string: 0x7ff5f2e33c90, 0x7fff59937a48 strong string: 0x7ff5f2e33c90, 0x7ff5f2e2aec8 copy string: 0x7ff5f2e2aee0, 0x7ff5f2e2aed0

可以發(fā)現(xiàn),此時(shí)copy屬性字符串已不再指向string字符串對象,而是深拷貝了string字符串,并讓_copyedString對象指向這個(gè)字符串。在MRC環(huán)境下,打印兩者的引用計(jì)數(shù),可以看到string對象的引用計(jì)數(shù)是2,而_copyedString對象的引用計(jì)數(shù)是1。

此時(shí),我們?nèi)绻バ薷膕tring字符串的話,可以看到:因?yàn)開strongString與string是指向同一對象,所以_strongString的值也會跟隨著改變(需要注意的是,此時(shí)_strongString的類型實(shí)際上是NSMutableString,而不是NSString);而_copyedString是指向另一個(gè)對象的,所以并不會改變。

結(jié)論

由于NSMutableString是NSString的子類,所以一個(gè)NSString指針可以指向NSMutableString對象,讓我們的strongString指針指向一個(gè)可變字符串是OK的。

而上面的例子可以看出,當(dāng)源字符串是NSString時(shí),由于字符串是不可變的,所以,不管是strong還是copy屬性的對象,都是指向源對象,copy操作只是做了次淺拷貝。

當(dāng)源字符串是NSMutableString時(shí),strong屬性只是增加了源字符串的引用計(jì)數(shù),而copy屬性則是對源字符串做了次深拷貝,產(chǎn)生一個(gè)新的對象,且copy屬性對象指向這個(gè)新的對象。另外需要注意的是,這個(gè)copy屬性對象的類型始終是NSString,而不是NSMutableString,因此其是不可變的。

這里還有一個(gè)性能問題,即在源字符串是NSMutableString,strong是單純的增加對象的引用計(jì)數(shù),而copy操作是執(zhí)行了一次深拷貝,所以性能上會有所差異。而如果源字符串是NSString時(shí),則沒有這個(gè)問題。

所以,在聲明NSString屬性時(shí),到底是選擇strong還是copy,可以根據(jù)實(shí)際情況來定。不過,一般我們將對象聲明為NSString時(shí),都不希望它改變,所以大多數(shù)情況下,我們建議用copy,以免因可變字符串的修改導(dǎo)致的一些非預(yù)期問題。

關(guān)于字符串的內(nèi)存管理,還有些有意思的東西,可以參考NSString特性分析學(xué)習(xí)。

參考

NSString copy not copying?

NSString特性分析學(xué)習(xí)

NSString什么時(shí)候用copy,什么時(shí)候用strong

Foundation中的斷言處理

經(jīng)常在看一些第三方庫的代碼時(shí),或者自己在寫一些基礎(chǔ)類時(shí),都會用到斷言。所以在此總結(jié)一下Objective-C中關(guān)于斷言的一些問題。

Foundation中定義了兩組斷言相關(guān)的宏,分別是:

NSAssert / NSCAssert NSParameterAssert / NSCParameterAssert

這兩組宏主要在功能和語義上有所差別,這些區(qū)別主要有以下兩點(diǎn):

如果我們需要確保方法或函數(shù)的輸入?yún)?shù)的正確性,則應(yīng)該在方法(函數(shù))的頂部使用NSParameterAssert / NSCParameterAssert;而在其它情況下,使用NSAssert / NSCAssert。

另一個(gè)不同是介于C和Objective-C之間。NSAssert / NSParameterAssert應(yīng)該用于Objective-C的上下文(方法)中,而NSCAssert / NSCParameterAssert應(yīng)該用于C的上下文(函數(shù))中。

當(dāng)斷言失敗時(shí),通常是會拋出一個(gè)如下所示的異常:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'true is not equal to false'

Foundation為了處理斷言,專門定義了一個(gè)NSAssertionHandler來處理斷言的失敗情況。NSAssertionHandler對象是自動創(chuàng)建的,用于處理失敗的斷言。當(dāng)斷言失敗時(shí),會傳遞一個(gè)字符串給NSAssertionHandler對象來描述失敗的原因。每個(gè)線程都有自己的NSAssertionHandler對象。當(dāng)調(diào)用時(shí),一個(gè)斷言處理器會打印包含方法和類(或函數(shù))的錯(cuò)誤消息,并引發(fā)一個(gè)NSInternalInconsistencyException異常。就像上面所看到的一樣。

我們很少直接去調(diào)用NSAssertionHandler的斷言處理方法,通常都是自動調(diào)用的。

NSAssertionHandler提供的方法并不多,就三個(gè),如下所示:

  1. // 返回與當(dāng)前線程的NSAssertionHandler對象。 

  2. // 如果當(dāng)前線程沒有相關(guān)的斷言處理器,則該方法會創(chuàng)建一個(gè)并指定給當(dāng)前線程 

  3. + (NSAssertionHandler *)currentHandler 

  4.  

  5. // 當(dāng)NSCAssert或NSCParameterAssert斷言失敗時(shí),會調(diào)用這個(gè)方法 

  6. - (void)handleFailureInFunction:(NSString *)functionName file:(NSString *)object lineNumber:(NSInteger)fileName description:(NSString *)line, format,... 

  7.  

  8. // 當(dāng)NSAssert或NSParameterAssert斷言失敗時(shí),會調(diào)用這個(gè)方法 

  9. - (void)handleFailureInMethod:(SEL)selector object:(id)object file:(NSString *)fileName lineNumber:(NSInteger)line description:(NSString *)format, ...

另外,還定義了一個(gè)常量字符串,

NSString * const NSAssertionHandlerKey;

主要是用于在線程的threadDictionary字典中獲取或設(shè)置斷言處理器。

關(guān)于斷言,還需要注意的一點(diǎn)是在Xcode 4.2以后,在release版本中斷言是默認(rèn)關(guān)閉的,這是由宏NS_BLOCK_ASSERTIONS來處理的。也就是說,當(dāng)編譯release版本時(shí),所有的斷言調(diào)用都是無效的。

我們可以自定義一個(gè)繼承自NSAssertionHandler的斷言處理類,來實(shí)現(xiàn)一些我們自己的需求。如Mattt Thompson的NSAssertionHandler實(shí)例一樣:

  1. @interface LoggingAssertionHandler : NSAssertionHandler 

  2. @end 

  3.  

  4. @implementation LoggingAssertionHandler 

  5.  

  6. - (void)handleFailureInMethod:(SEL)selector 

  7. object:(id)object 

  8. file:(NSString *)fileName 

  9. lineNumber:(NSInteger)line 

  10. description:(NSString *)format, ... 

  11. NSLog(@"NSAssert Failure: Method %@ for object %@ in %@#%i", NSStringFromSelector(selector), object, fileName, line); 

  12.  

  13. - (void)handleFailureInFunction:(NSString *)functionName 

  14. file:(NSString *)fileName 

  15. lineNumber:(NSInteger)line 

  16. description:(NSString *)format, ... 

  17. NSLog(@"NSCAssert Failure: Function (%@) in %@#%i", functionName, fileName, line); 

  18.  

  19. @end

上面說過,每個(gè)線程都有自己的斷言處理器。我們可以通過為線程的threadDictionary字典中的NSAssertionHandlerKey指定一個(gè)新值,來改變線程的斷言處理器。

如下代碼所示:

  1. - (BOOL)application:(UIApplication *)application 

  2. didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 

  3. NSAssertionHandler *assertionHandler = [[LoggingAssertionHandler alloc] init]; 

  4. [[[NSThread currentThread] threadDictionary] setValue:assertionHandler 

  5. forKey:NSAssertionHandlerKey]; 

  6. // ... 

  7.  

  8. return YES; 

  9. }

而什么時(shí)候應(yīng)該使用斷言呢?通常我們期望程序按照我們的預(yù)期去運(yùn)行時(shí),如調(diào)用的參數(shù)為空時(shí)流程就無法繼續(xù)下去時(shí),可以使用斷言。但另一方面,我們也需要考慮,在這加斷言確實(shí)是需要的么?我們是否可以通過更多的容錯(cuò)處理來使程序正常運(yùn)行呢?

Mattt Thompson在NSAssertionHandler中的倒數(shù)第二段說得挺有意思,在此摘抄一下:

But if we look deeper into NSAssertionHandler—and indeed, into our own hearts, there are lessons to be learned about our capacity for kindness and compassion; about our ability to forgive others, and to recover from our own missteps. We can't be right all of the time. We all make mistakes. By accepting limitations in ourselves and others, only then are we able to grow as individuals.

參考

NSAssertionHandler

NSAssertionHandler Class Reference

IBOutletCollection

在IB與相關(guān)文件做連接時(shí),我們經(jīng)常會用到兩個(gè)關(guān)鍵字:IBOutlet和IBAction。經(jīng)常用xib或storyboard的童鞋應(yīng)該用這兩上關(guān)鍵字非常熟悉了。不過UIKit還提供了另一個(gè)偽關(guān)鍵字IBOutletCollection,我們使用這個(gè)關(guān)鍵字,可以將界面上一組相同的控件連接到同一個(gè)數(shù)組中。

我們先來看看這個(gè)偽關(guān)鍵字的定義,可以從UIKit.framework的頭文件UINibDeclarations.h找到如下定義:

#ifndef IBOutletCollection #define IBOutletCollection(ClassName) #endif

另外,在Clang源碼中,有更安全的定義方式,如下所示:

#define IBOutletCollection(ClassName) __attribute__((iboutletcollection(ClassName)))

從上面的定義可以看到,與IBOutlet不同的是,IBOutletCollection帶有一個(gè)參數(shù),該參數(shù)是一個(gè)類名。

通常情況下,我們使用一個(gè)IBOutletCollection屬性時(shí),屬性必須是strong的,且類型是NSArray,如下所示:

@property (strong, nonatomic) IBOutletCollection(UIScrollView) NSArray *scrollViews;

假定我們的xib文件中有三個(gè)橫向的scrollView,我們便可以將這三個(gè)scrollView都連接至scrollViews屬性,然后在我們的代碼中便可以做一些統(tǒng)一處理,如下所示:

- (void)setupScrollViewImages { for (UIScrollView *scrollView in self.scrollViews) { [self.imagesData enumerateObjectsUsingBlock:^(NSString *imageName, NSUInteger idx, BOOL *stop) { UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(scrollView.frame) * idx, 0, CGRectGetWidth(scrollView.frame), CGRectGetHeight(scrollView.frame))]; imageView.contentMode = UIViewContentModeScaleAspectFill; imageView.image = [UIImage imageNamed:imageName]; [scrollView addSubview:imageView]; }]; } }

這段代碼會影響到三個(gè)scrollView。這樣做的好處是我們不需要手動通過addObject:方法將scrollView添加到scrollViews中。

不過在使用IBOutletCollection時(shí),需要注意兩點(diǎn):

IBOutletCollection集合中對象的順序是不確定的。我們通過調(diào)試方法可以看到集合中對象的順序跟我們連接的順序是一樣的。但是這個(gè)順序可能會因?yàn)椴煌姹镜腦code而有所不同。所以我們不應(yīng)該試圖在代碼中去假定這種順序。

不管IBOutletCollection(ClassName)中的控件是什么,屬性的類型始終是NSArray。實(shí)際上,我們可以聲明是任何類型,如NSSet,NSMutableArray,甚至可以是UIColor,但不管我們在此設(shè)置的是什么類,IBOutletCollection屬性總是指向一個(gè)NSArray數(shù)組。

關(guān)于第二點(diǎn),我們以上面的scrollViews為例,作如下修改:

@property (strong, nonatomic) IBOutletCollection(UIScrollView) NSSet *scrollViews;

實(shí)際上我們在控制臺打印這個(gè)scrollViews時(shí),結(jié)果如下所示:

(lldb) po self.scrollViews <__NSArrayI 0x1740573d0>( <UIScrollView: 0x12d60d770; frame = (0 0; 320 162); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x1740574f0>; layer = <CALayer: 0x174229480>; contentOffset: {0, 0}; contentSize: {0, 0}>, <UIScrollView: 0x12d60dee0; frame = (0 0; 320 161); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x174057790>; layer = <CALayer: 0x1742297c0>; contentOffset: {0, 0}; contentSize: {0, 0}>, <UIScrollView: 0x12d60e650; frame = (0 0; 320 163); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x1740579a0>; layer = <CALayer: 0x1742298e0>; contentOffset: {0, 0}; contentSize: {0, 0}> )

可以看到,它指向的是一個(gè)NSArray數(shù)組。

另外,IBOutletCollection實(shí)際上在iOS 4版本中就有了。不過,現(xiàn)在的Objective-C已經(jīng)支持object literals了,所以定義數(shù)組可以直接用@[],方便了許多。而且object literals方式可以添加不在xib中的用代碼定義的視圖,所以顯得更加靈活。當(dāng)然,兩種方式選擇哪一種,就看我們自己的實(shí)際需要和喜好了。

參考

IBAction / IBOutlet / IBOutletCollection

IBOutletCollection.m

NSRecursiveLock遞歸鎖的使用

NSRecursiveLock實(shí)際上定義的是一個(gè)遞歸鎖,這個(gè)鎖可以被同一線程多次請求,而不會引起死鎖。這主要是用在循環(huán)或遞歸操作中。我們先來看一個(gè)示例:

  1. NSLock *lock = [[NSLock alloc] init]; 

  2.  

  3. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

  4.  

  5. static void (^RecursiveMethod)(int); 

  6.  

  7. RecursiveMethod = ^(int value) { 

  8.  

  9. [lock lock]; 

  10. if (value > 0) { 

  11.  

  12. NSLog(@"value = %d", value); 

  13. sleep(2); 

  14. RecursiveMethod(value - 1); 

  15. [lock unlock]; 

  16. }; 

  17.  

  18. RecursiveMethod(5); 

  19. });

這段代碼是一個(gè)典型的死鎖情況。在我們的線程中,RecursiveMethod是遞歸調(diào)用的。所以每次進(jìn)入這個(gè)block時(shí),都會去加一次鎖,而從第二次開始,由于鎖已經(jīng)被使用了且沒有解鎖,所以它需要等待鎖被解除,這樣就導(dǎo)致了死鎖,線程被阻塞住了。調(diào)試器中會輸出如下信息:

value = 5 *** -[NSLock lock]: deadlock (<NSLock: 0x1700ceee0> '(null)') *** Break on _NSLockError() to debug.

在這種情況下,我們就可以使用NSRecursiveLock。它可以允許同一線程多次加鎖,而不會造成死鎖。遞歸鎖會跟蹤它被lock的次數(shù)。每次成功的lock都必須平衡調(diào)用unlock操作。只有所有達(dá)到這種平衡,鎖***才能被釋放,以供其它線程使用。

所以,對上面的代碼進(jìn)行一下改造,

NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];

這樣,程序就能正常運(yùn)行了,其輸出如下所示:

value = 5 value = 4 value = 3 value = 2 value = 1

NSRecursiveLock除了實(shí)現(xiàn)NSLocking協(xié)議的方法外,還提供了兩個(gè)方法,分別如下:

  1. // 在給定的時(shí)間之前去嘗試請求一個(gè)鎖 

  2. - (BOOL)lockBeforeDate:(NSDate *)limit 

  3.  

  4. // 嘗試去請求一個(gè)鎖,并會立即返回一個(gè)布爾值,表示嘗試是否成功 

  5. - (BOOL)tryLock 

  6.  

  7. 這兩個(gè)方法都可以用于在多線程的情況下,去嘗試請求一個(gè)遞歸鎖,然后根據(jù)返回的布爾值,來做相應(yīng)的處理。如下代碼所示: 

  8.  

  9. NSRecursiveLock *lock = [[NSRecursiveLock alloc] init]; 

  10.  

  11. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

  12.  

  13. static void (^RecursiveMethod)(int); 

  14.  

  15. RecursiveMethod = ^(int value) { 

  16.  

  17. [lock lock]; 

  18. if (value > 0) { 

  19.  

  20. NSLog(@"value = %d", value); 

  21. sleep(2); 

  22. RecursiveMethod(value - 1); 

  23. [lock unlock]; 

  24. }; 

  25.  

  26. RecursiveMethod(5); 

  27. }); 

  28.  

  29. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

  30.  

  31. sleep(2); 

  32. BOOL flag = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]]; 

  33. if (flag) { 

  34. NSLog(@"lock before date"); 

  35.  

  36. [lock unlock]; 

  37. } else { 

  38. NSLog(@"fail to lock before date"); 

  39. });

在前面的代碼中,我們又添加了一段代碼,增加一個(gè)線程來獲取遞歸鎖。我們在第二個(gè)線程中嘗試去獲取遞歸鎖,當(dāng)然這種情況下是會失敗的,輸出結(jié)果如下:

value = 5 value = 4 fail to lock before date value = 3 value = 2 value = 1

另外,NSRecursiveLock還聲明了一個(gè)name屬性,如下:

@property(copy) NSString *name

我們可以使用這個(gè)字符串來標(biāo)識一個(gè)鎖。Cocoa也會使用這個(gè)name作為錯(cuò)誤描述信息的一部分。

參考

NSRecursiveLock Class Reference

Objective-C中不同方式實(shí)現(xiàn)鎖(二)

NSHashTable

在看KVOController的代碼時(shí),又看到了NSHashTable這個(gè)類,所以就此整理一下。

NSHashTable效仿了NSSet(NSMutableSet),但提供了比NSSet更多的操作選項(xiàng),尤其是在對弱引用關(guān)系的支持上,NSHashTable在對象/內(nèi)存處理時(shí)更加的靈活。相較于NSSet,NSHashTable具有以下特性:

NSSet(NSMutableSet)持有其元素的強(qiáng)引用,同時(shí)這些元素是使用hash值及isEqual:方法來做hash檢測及判斷是否相等的。

NSHashTable是可變的,它沒有不可變版本。

它可以持有元素的弱引用,而且在對象被銷毀后能正確地將其移除。而這一點(diǎn)在NSSet是做不到的。

它的成員可以在添加時(shí)被拷貝。

它的成員可以使用指針來標(biāo)識是否相等及做hash檢測。

它可以包含任意指針,其成員沒有限制為對象。我們可以配置一個(gè)NSHashTable實(shí)例來操作任意的指針,而不僅僅是對象。

初始化NSHashTable時(shí),我們可以設(shè)置一個(gè)初始選項(xiàng),這個(gè)選項(xiàng)確定了這個(gè)NSHashTable對象后面所有的行為。這個(gè)選項(xiàng)是由NSHashTableOptions枚舉來定義的,如下所示:

enum {  // 默認(rèn)行為,強(qiáng)引用集合中的對象,等同于NSSet NSHashTableStrongMemory = 0,  // 在將對象添加到集合之前,會拷貝對象 NSHashTableCopyIn = NSPointerFunctionsCopyIn,  // 使用移位指針(shifted pointer)來做hash檢測及確定兩個(gè)對象是否相等; // 同時(shí)使用description方法來做描述字符串 NSHashTableObjectPointerPersonality = NSPointerFunctionsObjectPointerPersonality,  // 弱引用集合中的對象,且在對象被釋放后,會被正確的移除。 NSHashTableWeakMemory = NSPointerFunctionsWeakMemory }; typedef NSUInteger NSHashTableOptions;

當(dāng)然,我們還可以使用NSPointerFunctions來初始化,但只有使用NSHashTableOptions定義的這些值,才能確保NSHashTable的各個(gè)API可以正確的工作&mdash;包括拷貝、歸檔及快速枚舉。

個(gè)人認(rèn)為NSHashTable吸引人的地方在于可以持有元素的弱引用,而且在對象被銷毀后能正確地將其移除。我們來寫個(gè)示例:

  1. // 具體調(diào)用如下 

  2. @implementation TestHashAndMapTableClass { 

  3.  

  4. NSMutableDictionary *_dic; 

  5. NSSet *_set; 

  6.  

  7. NSHashTable *_hashTable; 

  8.  

  9. - (instancetype)init { 

  10.  

  11. self = [super init]; 

  12.  

  13. if (self) { 

  14.  

  15. [self testWeakMemory]; 

  16.  

  17. NSLog(@"hash table [init]: %@", _hashTable); 

  18.  

  19. return self; 

  20.  

  21. - (void)testWeakMemory { 

  22.  

  23. if (!_hashTable) { 

  24. _hashTable = [NSHashTable weakObjectsHashTable]; 

  25.  

  26. NSObject *obj = [[NSObject alloc] init]; 

  27.  

  28. [_hashTable addObject:obj]; 

  29.  

  30. NSLog(@"hash table [testWeakMemory] : %@", _hashTable); 

  31.  

  32. 這段代碼的輸出結(jié)果如下: 

  33.  

  34. hash table [testWeakMemory] : NSHashTable { 

  35. [6] <NSObject: 0x7fa2b1562670> 

  36. hash table [init]: NSHashTable { 

  37. }

可以看到,在離開testWeakMemory方法,obj對象被釋放,同時(shí)對象在集合中的引用也被安全的刪除。

這樣看來,NSHashTable似乎比NSSet(NSMutableSet)要好啊。那是不是我們就應(yīng)用都使用NSHashTable呢?Peter Steinberger在The Foundation Collection Classes給了我們一組數(shù)據(jù),顯示在添加對象的操作中,NSHashTable所有的時(shí)間差不多是NSMutableSet的2倍,而在其它操作中,性能大體相近。所以,如果我們只需要NSSet的特性,就盡量用NSSet。

另外,Mattt Thompson在NSHashTable & NSMapTable的結(jié)尾也寫了段挺有意思的話,在此直接摘抄過來:

As always, it's important to remember that programming is not about being clever: always approach a problem from the highest viable level of abstraction. NSSet and NSDictionary are great classes. For 99% of problems, they are undoubtedly the correct tool for the job. If, however, your problem has any of the particular memory management constraints described above, then NSHashTable & NSMapTable may be worth a look.

參考

NSHashTable Class Reference

NSHashTable & NSMapTable

NSHashTable & NSMapTable

The Foundation Collection Classes

零碎

(一) “Unknown class XXViewController in Interface Builder file.”“ 問題處理

最近在靜態(tài)庫中寫了一個(gè)XXViewController類,然后在主工程的xib中,將xib的類指定為XXViewController,程序運(yùn)行時(shí),報(bào)了如下錯(cuò)誤:

Unknown class XXViewController in Interface Builder file.

之前也遇到這個(gè)問題,但已記得不太清楚,所以又開始在stackoverflow上找答案。

其實(shí)這個(gè)問題與Interface Builder無關(guān),最直接的原因還是相關(guān)的symbol沒有從靜態(tài)庫中加載進(jìn)來。這種問題的處理就是在Target的”Build Setting”&ndash;>“Other Link Flags”中加上”-all_load -ObjC”這兩個(gè)標(biāo)識位,這樣就OK了。

(二)關(guān)于Unbalanced calls to begin/end appearance transitions for &hellip;問題的處理

我們的某個(gè)業(yè)務(wù)有這么一個(gè)需求,進(jìn)入一個(gè)列表后需要立馬又push一個(gè)web頁面,做一些活動的推廣。在iOS 8上,我們的實(shí)現(xiàn)是一切OK的;但到了iOS 7上,就發(fā)現(xiàn)這個(gè)web頁面push不出來了,同時(shí)控制臺給了一條警告消息,即如下:

Unbalanced calls to begin/end appearance transitions for ...

在這種情況下,點(diǎn)擊導(dǎo)航欄中的返回按鈕時(shí),直接顯示一個(gè)黑屏。

我們到stackoverflow上查了一下,有這么一段提示:

occurs when you try and display a new viewcontroller before the current view controller is finished displaying.

意思是說在當(dāng)前視圖控制器完成顯示之前,又試圖去顯示一個(gè)新的視圖控制器。

于是我們?nèi)ヅ挪榇a,果然發(fā)現(xiàn),在viewDidLoad里面去做了次網(wǎng)絡(luò)請求操作,且請求返回后就去push這個(gè)web活動推廣頁。此時(shí),當(dāng)前的視圖控制器可能并未顯示完成(即未完成push操作)。

Basically you are trying to push two view controllers onto the stack at almost the same time.

當(dāng)幾乎同時(shí)將兩個(gè)視圖控制器push到當(dāng)前的導(dǎo)航控制器棧中時(shí),或者同時(shí)pop兩個(gè)不同的視圖控制器,就會出現(xiàn)不確定的結(jié)果。所以我們應(yīng)該確保同一時(shí)間,對同一個(gè)導(dǎo)航控制器棧只有一個(gè)操作,即便當(dāng)前的視圖控制器正在動畫過程中,也不應(yīng)該再去push或pop一個(gè)新的視圖控制器。

所以***我們把web活動的數(shù)據(jù)請求放到了viewDidAppear里面,并做了些處理,這樣問題就解決了。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“不可錯(cuò)過的iOS開發(fā)技巧有哪些”這篇文章對大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

網(wǎng)站標(biāo)題:不可錯(cuò)過的iOS開發(fā)技巧有哪些
網(wǎng)站URL:http://aaarwkj.com/article38/gpjosp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、網(wǎng)站導(dǎo)航、定制開發(fā)、響應(yīng)式網(wǎng)站外貿(mào)建站、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
国产精品三级国产精品高| 色综合视频二区偷拍在线| 岛国大片日韩在线观看| 91九色国产原创在线观看| 日韩日美日韩av影视| 一区二区视频精品在线观看| 一区二区三区四区中文在线| 亚洲午夜一区二区三区精品影院| 可以免费看黄的网久久| 日韩av一区二区在线| 日本少妇熟女一区二区| 午夜av一区二区三区| 成人在线午夜你懂的视频| 中文字幕一区中出爽亚洲| 天堂网av高清在线播放| 精品午夜免费福利视频| 国产91精品成人在线观看 | 久久最新视频中文字幕| 十八禁在线观看国产一区| 亚洲av优选在线观看精品| 国产剧情av一区在线观看| 精品人妻一区二区三区| 国产女片xb内射在线| 国产精品日韩av一区二区| 好看的中文字幕人妻少妇| 欧美色高清视频在线播放| 18末年禁止观看免费软件| 亚洲乱码中文字幕在线观看| 国产精品亚洲精品日韩在线| 国产精品欧美日韩精品| 99热久久精品免费精品| 午夜一区二区精品视频国产| 亚洲综合另类视频在线观看| 亚洲视频在线男人天堂| 国产精品国产三级国产av丨| 国产精品久久99一区| 国产精品成人免费久久黄| 日本av免费观看一区二区| 精品国产50部农村老熟女av| 亚洲欧美国产在线日韩| 久久精品亚洲熟女av蜜臀|