iOS开发——淫技篇&iOS开发中各种淫技总结(五)

淫技篇&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》了解一二。

1、Xcode自动生成

  • Xcode会在编译工程或者归档时自动为我们生成.dSYM文件,当然我们也可以通过更改Xcode的若干项Build Settings来阻止它那么干。

2、手动生成

  • 另一种方式是通过命令行从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

1、 符号表堆栈地址计算方式


想利用符号表解析出崩溃对应位置,需要计算出符号表中对应的崩溃堆栈地址。而从上述堆栈中第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的小对勾的颜色改成别的颜色

_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这个编译器标识,它会在运行时跳过在当前的类对象中寻找方法的过程。
时间: 2024-10-07 19:21:32

iOS开发——淫技篇&iOS开发中各种淫技总结(五)的相关文章

IOS开发数据存储篇—IOS中的几种数据存储方式

IOS开发数据存储篇—IOS中的几种数据存储方式 发表于2016/4/5 21:02:09  421人阅读 分类: 数据存储 在项目开发当中,我们经常会对一些数据进行本地缓存处理.离线缓存的数据一般都保存在APP所在的沙盒之中.一般有以下几种: 1.PList(XML属性列表) 在使用plist进行数据存储和读取,只适用于系统自带的一些常用类型才能用,且必须先获取路径相对麻烦 //写入文件 NSString *doc = [NSSearchPathForDirectoriesInDomains(

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(六)

iOS开发中各种淫技总结(六) swift中指针的使用 在 Swift 中,指针都使用一个特殊的类型来表示,那就是 UnsafePointer<T>.遵循了 Cocoa 的一贯不可变原则,UnsafePointer<T> 也是不可变的.当然对应地,它还有一个可变变体,UnsafeMutablePointer<T>.绝大部分时间里,C 中的指针都会被以这两种类型引入到 Swift 中:C 中 const 修饰的指针对应 UnsafePointer (最常见的应该就是 C

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(四)

iOS开发中各种淫技总结(四) 一:@autoclosure将一段代码块活着一句表达式自动的封装成一个闭包 func logIfTrue(predicate: () -> Bool) { if predicate() { print("True") } } 调用 logIfTrue({return 2 > 1}) 简写:logIfTrue{2 > 1} 在predicate加上@autoclosure调用的时候就可以省略{}直接使用logIfTrue(2>1)

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(二)

iOS开发中各种淫技总结(二) 先来张笔者电脑上面安装的Mac app 一:for .. in 的内部实现(swift): 1 var g = array.generate() 2 while let obj = g.next() { 3 4 5 print(obj) } 6 二:map/Fileter/Reduce map map方法,其获取一个闭包表达式作为其唯一参数. 数组中的每一个元素调用一次该闭包函数,并返回该元素所映射的值(也可以是不同类型的值). 具体的映射方式和返回值类型由闭包来

iOS开发——淫技篇&amp;iOS开发中各种淫技总结(三)

iOS开发中各种淫技总结(三) 一:send和awk解释 sed -n p filenamesed ----------------------------是一个流编辑器(stream editor) awk ‘BEGIN {print “Hellow"}'awk --------是一种用于处理文本的编程语言工具. 二:传值方式总结 KVO底层会动态长生新的类,只能坚挺属性(一个对象的属性能背多个兑现监听,一个对象能监听多个对象的其他属性) kvc/kvo底层是基于runtime 代理,规范,代

C# Xamarin移动开发基础进修篇

一.课程介绍 英文原文:C# is the best language for mobile app development. Anything you can do in Objective-C, Swift or Java, you can do in C#. 中文译意:C#是移动应用程序开发的最佳语言. 在Objective-C,Swift或Java中你可以做的任何事情,你都可以在C#中完成. 1).本次分享课程适合人群如下: 1. 热爱Xamarin跨平台移动开发. 2.进一步了解和学习

C# Xamarin移动开发项目实战篇

一.课程介绍 在前面阿笨的<C# Xamarin移动开发基础进修篇>课程中,大家已经熟悉和了解了Xamarin移动App开发的基础知识和原理.本次分享课<C# Xamarin移动开发项目实战篇>,阿笨将直接带领大家进入Xamarin for android的实战项目环节,真真体验一下xamarin开发的魅力吧. 由于阿笨学习Xamarin也是"半路出家","赶鸭子上架"的状态,视频教学中关于Xamarin for Android的知识点难免有

XE6移动开发环境搭建之IOS篇(7):在Mac OSX 10.8中安装Xcode4.6.3(有图有真相)

XE6移动开发环境搭建之IOS篇(7):在Mac OSX 10.8中安装Xcode4.6.3(有图有真相) 2014-08-23 21:37 网上能找到的关于Delphi XE系列的移动开发环境的相关文章甚少,本文尽量以详细的图文内容.傻瓜式的表达来告诉你想要的答案. 在安装Xcode前,我们先了解下Mac下如何卸载U盘!在VM9下,同一时间内,一个物理设备只能由一个系统去独占,无论是物理机还是虚拟机.我们可以了解一下虚拟机加载U盘的规则:    1.在虚拟机中加载U盘时,会自动将U盘从Wind

XE6移动开发环境搭建之IOS篇(7):在Mac OSX 10.8中安装XE6的PAServer(有图有真相)

XE6移动开发环境搭建之IOS篇(7):在Mac OSX 10.8中安装XE6的PAServer(有图有真相) 2014-08-22 21:06 网上能找到的关于Delphi XE系列的移动开发环境的相关文章甚少,本文尽量以详细的内容.傻瓜式的表达来告诉你想要的答案. 在安装PAServer前,我们先配置一下MAC的IP,给定一个固定的内网IP,以便我们的XE6能更好地连接它!------------------------------------------------------------