iOS開發-開發總結

ARC的使用:
ARC並不能避免全部的內存泄露。使用ARC以後,工程中可能還會有內存泄露,不過引發這些內存泄露的主要緣由是:block,retain循環,對CoreFoundation對象(一般是C結構)管理不善,以及真的是代碼沒寫好。

 
reuseIdentifier

在iOS程序開發中一個廣泛性的錯誤就是沒有正確的爲UITableViewCells、UICollectionViewCells和UITableViewHeaderFooterViews設置reuseIdentifier。
 
爲 了得到最佳性能,當在tableView:cellForRowAtIndexPath:方法中返回cell時,table view的數據源通常會重用UITableViewCell對象。table view維護着UITableViewCell對象的一個隊列或者列表,這些數據源已經被標記爲重用了。
 
如 果沒有使用reuseIdentifier會發生什麼?若是你在程序中沒有使用reuseIdentifier,table view每次顯示一個row時,都會配置一個全新的cell。這實際上是一個很是消耗資源的操做,而且會影響程序中table view滾動的效率。
 
自iOS 7以來,你可能還但願header和footer views,以及UICollectionView的cell和supplementary views。
 
爲了使用reuseIdentifiers,在table view請求一個新的cell時,在數據源中調用下面的方法:
static NSString *CellIdentifier = @"Cell";  
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; 
如 果table view維護的UITableViewCell隊列或列表中有可用的cell,則從隊列從移除一個已經存在的cell,若是沒有的話,就從以前註冊的 nib文件或類中建立一個新的cell。若是沒有能夠重用的cell,而且沒有註冊nib文件或類,tableview的 dequeueReusableCellWithIdentifier:方法會返回一個nil。
 
 

 
儘可能將view設置爲Opaque
 
若是view是不透明的,那麼應該將其opaque屬性設置爲YES。爲何要這樣作呢?這樣設置可讓系統以最優的方式來繪製view。opaque屬性能夠在Interface Builder或代碼中設置。
 
蘋果的官方文檔對opaque屬性有以下解釋:
This property provides a hint to the drawing system as to how it should treat the view. If set to YES, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance. If set to NO, the drawing system composites the view normally with other content. The default value of this property is YES.
(opaque屬性提示繪製系統如何處理view。若是opaque設置爲YES,繪圖系統會將view看爲徹底不透明,這樣繪圖系統就能夠優化一些繪製操做以提高性能。若是設置爲NO,那麼繪圖系統結合其它內容來處理view。默認狀況下,這個屬性是YES。)
 
如 果屏幕是靜止的,那麼這個opaque屬性的設置與否不是一個大問題。可是,若是view是嵌入到scroll view中的,或者是複雜動畫的一部分,不將設置這個屬性的話確定會影響程序的性能!能夠經過模擬器的Debug\Color Blended Layers選項來查看哪些view沒有設置爲不透明。爲了程序的性能,儘量的將view設置爲不透明!
I’m sorry that I long ago coined the term 「objects」 for this topic because it gets many people to focus on the lesser idea. The big idea is 「messaging」 – that is what the kernal[sic] of Smalltalk is all about... The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.

 

Alan Kay 曾屢次強調 Smalltalk 的核心不是面向對象,面向對象只是 the lesser ideas,消息傳遞纔是 the big idea。
 
 
dSYM文件的生成

符號表文件.dSYM其實是從Mach-O文件中抽取調試信息而獲得的文件目錄,實際用於保存調試信息的問價是DWARF,其出身能夠從蘋果員工的文章《Apple’s 「Lazy」 DWARF Scheme》瞭解一二。

一、Xcode自動生成
  • Xcode會在編譯工程或者歸檔時自動爲咱們生成.dSYM文件,固然咱們也能夠經過更改Xcode的若干項Build Settings來阻止它那麼幹。

二、手動生成
  • 另外一種方式是經過命令行從Mach-O文件中手工提取,好比:

$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/dsymutil /Users/wangzz/Library/Developer/Xcode/DerivedData/YourApp-cqvijavqbptjyhbwewgpdmzbmwzk/Build/Products/Debug-iphonesimulator/YourApp.app/YourApp -o YourApp.dSYM
該方式經過Xcode提供的工具dsymutil,從項目編譯結果.app目錄下的Mach-O文件中提取出調試符號表文件。實際上Xcode也是經過這種方式來生成符號表文件。
 
 
計算崩潰符號表地址

如下面的崩潰堆棧爲例:
  • Thread 0:
  • 0   libobjc.A.dylib                   0x33f10f60 0x33efe000 + 77664
  • 1   Foundation                        0x273526ac 0x2734a000 + 34476
  • 2   Foundation                        0x27355c3e 0x2734a000 + 48190
  • 3   UIKit                             0x29ef9d1c 0x29bbc000 + 3398940
  • 4   UIKit                             0x29ef9c9a 0x29bbc000 + 3398810
  • 5   UIKit                             0x29ef954c 0x29bbc000 + 3396940
  • 6   UIKit                             0x29c3a16a 0x29bbc000 + 516458
  • 7   UIKit                             0x29e4b8e6 0x29bbc000 + 2685158
  • 8   UIKit                             0x29c3a128 0x29bbc000 + 516392
  • 9   Your                              0x000f0846 0xa2000 + 321606
  • 10  UIKit                             0x29e90fb2 0x29bbc000 + 2969522
  • 11  UIKit                             0x29e91076 0x29bbc000 + 2969718
  • 12  UIKit                             0x29e867cc 0x29bbc000 + 2926540
  • 13  UIKit                             0x29c9e8ea 0x29bbc000 + 927978
  • 14  UIKit                             0x29bc8a6a 0x29bbc000 + 51818
  • 15  QuartzCore                        0x295f0a08 0x295e4000 + 51720
  • 16  QuartzCore                        0x295ec3e0 0x295e4000 + 33760
  • 17  QuartzCore                        0x295ec268 0x295e4000 + 33384
  • 18  QuartzCore                        0x295ebc4c 0x295e4000 + 31820
  • 19  QuartzCore                        0x295eba50 0x295e4000 + 31312
  • 20  QuartzCore                        0x295e5928 0x295e4000 + 6440
  • 21  CoreFoundation                    0x266d0d92 0x26604000 + 839058
  • 22  CoreFoundation                    0x266ce44e 0x26604000 + 828494
  • 23  CoreFoundation                    0x266ce856 0x26604000 + 829526
  • 24  CoreFoundation                    0x2661c3bc 0x26604000 + 99260
  • 25  CoreFoundation                    0x2661c1ce 0x26604000 + 98766
  • 26  GraphicsServices                  0x2da1a0a4 0x2da11000 + 37028
  • 27  UIKit                             0x29c2a7ac 0x29bbc000 + 452524
  • 28  Your                              0x0024643a 0xa2000 + 1721402
  • 29  libdyld.dylib                     0x34484aac 0x34483000 + 6828
一、 符號表堆棧地址計算方式

要 想利用符號表解析出崩潰對應位置,須要計算出符號表中對應的崩潰堆棧地址。而從上述堆棧中第9行能夠看到,應用崩潰發生在運行時地址 0x000f0846,該進程的運行時起始地址是0xa2000,崩潰處距離進程起始地址的偏移量爲十進制的321606(對應十六進制爲 0x4E846)。三者對應關係:

0x000f0846 = 0xa2000 + 0x4E846
對應的公式爲:
  • 運行時堆棧地址 = 運行時起始地址 + 偏移量
崩潰堆棧中的起始地址和崩潰地址均爲運行時地址,根據虛擬內存偏移量不變原理,只要提供了符號表TEXT段的起始地址,再加上偏移量(這裏爲0x4E846)就能獲得符號表中的堆棧地址,即:
  • 符號表堆棧地址 = 符號表起始地址 + 偏移量
複製代碼
 
   self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
                                         initWithImage:img
                                         style:UIBarButtonItemStylePlain
                                         target:self
                                         action:@selector(onBack:)];
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
複製代碼

 

不新建一個Cell的狀況下調整separaLine的位置?
_myTableView.separatorInset = UIEdgeInsetsMake(0, 100, 0, 0);

 

滑動的時候隱藏navigationbar?
navigationController.hidesBarsOnSwipe = Yes
 
導航條返回鍵帶的title消失!
[[UIBarButtonItem appearance] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, -60)
                                                     forBarMetrics:UIBarMetricsDefault];
 
只用一個pan手勢來代替UISwipegesture的各個方向?
複製代碼
 1 - (void)pan:(UIPanGestureRecognizer *)sender
 2 {
 3 typedef NS_ENUM(NSUInteger, UIPanGestureRecognizerDirection) {
 4     UIPanGestureRecognizerDirectionUndefined,
 5     UIPanGestureRecognizerDirectionUp,
 6     UIPanGestureRecognizerDirectionDown,
 7     UIPanGestureRecognizerDirectionLeft,
 8     UIPanGestureRecognizerDirectionRight
 9 };
10 static UIPanGestureRecognizerDirection direction = UIPanGestureRecognizerDirectionUndefined;
11 switch (sender.state) {
12     case UIGestureRecognizerStateBegan: {
13         if (direction == UIPanGestureRecognizerDirectionUndefined) {
14             CGPoint velocity = [sender velocityInView:recognizer.view];
15             BOOL isVerticalGesture = fabs(velocity.y) > fabs(velocity.x);
16             if (isVerticalGesture) {
17                 if (velocity.y > 0) {
18                     direction = UIPanGestureRecognizerDirectionDown;
19                 } else {
20                     direction = UIPanGestureRecognizerDirectionUp;
21                 }
22             }
23             else {
24                 if (velocity.x > 0) {
25                     direction = UIPanGestureRecognizerDirectionRight;
26                 } else {
27                     direction = UIPanGestureRecognizerDirectionLeft;
28                 }
29             }
30         }
31         break;
32     }
33     case UIGestureRecognizerStateChanged: {
34         switch (direction) {
35             case UIPanGestureRecognizerDirectionUp: {
36                 [self handleUpwardsGesture:sender];
37                 break;
38             }
39             case UIPanGestureRecognizerDirectionDown: {
40                 [self handleDownwardsGesture:sender];
41                 break;
42             }
43             case UIPanGestureRecognizerDirectionLeft: {
44                 [self handleLeftGesture:sender];
45                 break;
46             }
47             case UIPanGestureRecognizerDirectionRight: {
48                 [self handleRightGesture:sender];
49                 break;
50             }
51             default: {
52                 break;
53             }
54         }
55         break;
56     }
57     case UIGestureRecognizerStateEnded: {
58         direction = UIPanGestureRecognizerDirectionUndefined;   
59         break;
60     }
61     default:
62         break;
63 }
64 }
複製代碼
 
改變uitextfield placeholder的顏色和位置

繼承uitextfield,重寫這個方法

1 - (void) drawPlaceholderInRect:(CGRect)rect {
2     [[UIColor blueColor] setFill];
3     [self.placeholder drawInRect:rect withFont:self.font lineBreakMode:UILineBreakModeTailTruncation alignment:self.textAlignment];
4 }
 
把navigationbar弄成透明的而不是帶模糊的效果
1 [self.navigationBar setBackgroundImage:[UIImage new]
2                          forBarMetrics:UIBarMetricsDefault];
3 self.navigationBar.shadowImage = [UIImage new];
4 self.navigationBar.translucent = YES;
 
statusbar是lightcontent的,結果用UIImagePickerController會致使個人statusbar的樣式變成黑色

1 - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
2 {
3     [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
4 }

 

把tableview裏cell的小對勾的顏色改爲別的顏色git

_mTableView.tintColor = [UIColor redColor];
 
一句話添加上拉刷新?(還有一個更好的MJRefresh你懂的)

1 https://github.com/samvermette/SVPullToRefresh
2 
3 [tableView addPullToRefreshWithActionHandler:^{
4 // prepend data to dataSource, insert cells at top of table view
5 // call [tableView.pullToRefreshView stopAnimating] when done
6 } position:SVPullToRefreshPositionBottom];
 
關於運行時
複製代碼
 1 unsigned int count;
 2     //獲取屬性列表
 3     objc_property_t *propertyList = class_copyPropertyList([self class], &count);
 4     for (unsigned int i=0; i<count; i++) {         const char *propertyname =" property_getName(propertyList[i]);"         nslog(@"property----="">%@", [NSString stringWithUTF8String:propertyName]);
 5     }
 6     //獲取方法列表
 7     Method *methodList = class_copyMethodList([self class], &count);
 8     for (unsigned int i; i<count; i++) {         method method =" methodList[i];"         nslog(@"method----="">%@", NSStringFromSelector(method_getName(method)));
 9     }
10     //獲取成員變量列表
11     Ivar *ivarList = class_copyIvarList([self class], &count);
12     for (unsigned int i; i<count; i++) {         ivar myivar =" ivarList[i];"         const char *ivarname =" ivar_getName(myIvar);"         nslog(@"ivar----="">%@", [NSString stringWithUTF8String:ivarName]);
13     }
14     //獲取協議列表
15     __unsafe_unretained Protocol **protocolList = class_copyProtocolList([self class], &count);
16     for (unsigned int i; i<count; i++) {         protocol *myprotocal =" protocolList[i];"         const char *protocolname =" protocol_getName(myProtocal);"         nslog(@"protocol----="">%@", [NSString stringWithUTF8String:protocolName]);
17  
複製代碼

 

方法調用
若是用實例對象調用實例方法,會到實例的isa指針指向的對象(也就是類對象)操做。

若是調用的是類方法,就會到類對象的isa指針指向的對象(也就是元類對象)中操做。
  • 首先,在相應操做的對象中的緩存方法列表中找調用的方法,若是找到,轉向相應實現並執行。
  • 若是沒找到,在相應操做的對象中的方法列表中找調用的方法,若是找到,轉向相應實現執行
  • 若是沒找到,去父類指針所指向的對象中執行1,2.
  • 以此類推,若是一直到根類還沒找到,轉向攔截調用。
  • 若是沒有重寫攔截調用的方法,程序報錯。
以上的過程給我帶來的啓發:
    1. 重寫父類的方法,並無覆蓋掉父類的方法,只是在當前類對象中找到了這個方法後就不會再去父類中找了。
    2. 若是想調用已經重寫過的方法的父類的實現,只需使用super這個編譯器標識,它會在運行時跳過在當前的類對象中尋找方法的過程。
相關文章
相關標籤/搜索