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这个编译器标识,它会在运行时跳过在当前的类对象中寻找方法的过程。
相关文章
相关标签/搜索