Snow Memory

雪忆, 如雪般单纯, 冷静思考.


  • 首页

  • 分类

  • 关于

  • 归档

  • 标签

button图文

发表于 Oct 3 2017

Button是我们平时用的最多的控件之一,经常会遇到图片文字位置的问题,用下面的方法一行代码就可以搞定

创建UIButton分类

.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSUInteger, DCDButtonEdgeInsetsStyle) {
DCDButtonEdgeInsetsStyleTop, // image在上,label在下
DCDButtonEdgeInsetsStyleLeft, // image在左,label在右
DCDButtonEdgeInsetsStyleBottom, // image在下,label在上
DCDButtonEdgeInsetsStyleRight // image在右,label在左
};
@interface UIButton (TitleImageSpacing)
/**
* 设置button的titleLabel和imageView的布局样式,及间距
*
* @param style titleLabel和imageView的布局样式
* @param space titleLabel和imageView的间距
*/
- (void)layoutButtonWithEdgeInsetsStyle:(DCDButtonEdgeInsetsStyle)style
imageTitleSpace:(CGFloat)space;
@end

.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#import "UIButton+TitleImageSpacing.h"
@implementation UIButton (TitleImageSpacing)
- (void)layoutButtonWithEdgeInsetsStyle:(DCDButtonEdgeInsetsStyle)style
imageTitleSpace:(CGFloat)space
{
// self.backgroundColor = [UIColor cyanColor];
/**
* 前置知识点:titleEdgeInsets是title相对于其上下左右的inset,跟tableView的contentInset是类似的,
* 如果只有title,那它上下左右都是相对于button的,image也是一样;
* 如果同时有image和label,那这时候image的上左下是相对于button,右边是相对于label的;title的上右下是相对于button,左边是相对于image的。
*/
// 1. 得到imageView和titleLabel的宽、高
CGFloat imageWith = self.imageView.frame.size.width;
CGFloat imageHeight = self.imageView.frame.size.height;
CGFloat labelWidth = 0.0;
CGFloat labelHeight = 0.0;
if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) {
// 由于iOS8中titleLabel的size为0,用下面的这种设置
labelWidth = self.titleLabel.intrinsicContentSize.width;
labelHeight = self.titleLabel.intrinsicContentSize.height;
} else {
labelWidth = self.titleLabel.frame.size.width;
labelHeight = self.titleLabel.frame.size.height;
}
// 2. 声明全局的imageEdgeInsets和labelEdgeInsets
UIEdgeInsets imageEdgeInsets = UIEdgeInsetsZero;
UIEdgeInsets labelEdgeInsets = UIEdgeInsetsZero;
// 3. 根据style和space得到imageEdgeInsets和labelEdgeInsets的值
switch (style) {
case DCDButtonEdgeInsetsStyleTop:
{
imageEdgeInsets = UIEdgeInsetsMake(-labelHeight-space/2.0, 0, 0, -labelWidth);
labelEdgeInsets = UIEdgeInsetsMake(0, -imageWith, -imageHeight-space/2.0, 0);
}
break;
case DCDButtonEdgeInsetsStyleLeft:
{
imageEdgeInsets = UIEdgeInsetsMake(0, -space/2.0, 0, space/2.0);
labelEdgeInsets = UIEdgeInsetsMake(0, space/2.0, 0, -space/2.0);
}
break;
case DCDButtonEdgeInsetsStyleBottom:
{
imageEdgeInsets = UIEdgeInsetsMake(0, 0, -labelHeight-space/2.0, -labelWidth);
labelEdgeInsets = UIEdgeInsetsMake(-imageHeight-space/2.0, -imageWith, 0, 0);
}
break;
case DCDButtonEdgeInsetsStyleRight:
{
imageEdgeInsets = UIEdgeInsetsMake(0, labelWidth+space/2.0, 0, -labelWidth-space/2.0);
labelEdgeInsets = UIEdgeInsetsMake(0, -imageWith-space/2.0, 0, imageWith+space/2.0);
}
break;
default:
break;
}
// 4. 赋值
self.titleEdgeInsets = labelEdgeInsets;
self.imageEdgeInsets = imageEdgeInsets;
}

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for (int i = 1; i < 5; i ++) {
UIButton *goBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 150 * i , 200, 100)];
goBtn.backgroundColor = [UIColor redColor];
[goBtn setTitle:@"👆微信好友👆" forState:UIControlStateNormal];
[goBtn setImage:[UIImage imageNamed:@"img_wechat"] forState:UIControlStateNormal];
if (i == 1) {
[goBtn layoutButtonWithEdgeInsetsStyle:DCDButtonEdgeInsetsStyleTop imageTitleSpace:10];
}else if (i == 2){
[goBtn layoutButtonWithEdgeInsetsStyle:DCDButtonEdgeInsetsStyleLeft imageTitleSpace:10];
}else if (i == 3){
[goBtn layoutButtonWithEdgeInsetsStyle:DCDButtonEdgeInsetsStyleBottom imageTitleSpace:10];
}else if (i == 4){
[goBtn layoutButtonWithEdgeInsetsStyle:DCDButtonEdgeInsetsStyleRight imageTitleSpace:10];
}
[self.view addSubview:goBtn];
}

效果图

button

性能优化小结

发表于 Sep 3 2017

性能优化小结

界面卡顿产生的原因

在VSync信号到来后,系统图形服务会通过CADisplayLink等机制通知App,App主线程开始在CPU中计算显示内容,比如视图的创建、布局计算、图片解码、文本绘制等。随后CPU会将计算好的内容提交到GPU去,由GPU进行变换、合成、渲染。随后GPU会把渲染结果提交到帧缓冲区去,等待下一次VSync信号到来时显示到屏幕上。由于垂直同步的机制,如果在一个VSync时间内,CPU或者GPU没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变。这就是界面卡顿的原因。

在开发中,CPU和GPU中任何一个压力过大,都会导致掉帧现象(FPS< 60)

CPU

加载资源,对象创建,对象调整,对象销毁,布局计算,Autolayout,文本计算,文本渲染,图片的解码, 图像的绘制(Core Graphics)都是在CPU上面进行的。

CPU资源消耗原因以及解决办法

1、对象的创建:

对象的创建会分配内存、设置属性等,会消耗CPU资源。所以尽量使用轻量对象代替,比如能用CALayer的时候尽量不用UIView,敏感位置能不用IB尽量使用纯代码手写。

推迟同一时间创建对象,推荐使用懒加载在需要使用时候创建对象。

2、对象调整

对 UIView 的这些属性进行调整时,消耗的资源要远大于一般的属性。对此你在应用中,应该尽量减少不必要的属性修改。

当视图层次调整时,UIView、CALayer 之间会出现很多方法调用与通知,所以在优化性能时,应该尽量避免调整视图层次、添加和移除视图。

3、对象销毁

当前类持有大量对象时候,其销毁时候的资源消耗就非常明显。建议创建销毁的异步队列,将需要销毁的对象放到队列中销毁。

4、布局计算

布局计算在UITableView使用中是最常见的消耗资源的地方。建议取到数据之后,异步进行计算布局并缓存下来,当复用Cell时候直接调用缓存数据。

5、AutoLayout

Autolayout 对于复杂视图来说常常会产生严重的性能问题,AutoLayout相对低效的原因是隐藏在底层的命名为”Cassowary“的约束求解系统,随着视图数量的增长,Autolayout 带来的 CPU 消耗会呈指数级上升,当Cell内约束超过25个的时候,会降低滑动的帧率。

具体:http://pilky.me/36/

6、文本的计算以及渲染

UI中存在大量的对于文本高度的适配,可以参考:用 [NSAttributedString boundingRectWithSize:options:context:] 来计算文本宽高,用 -[NSAttributedString drawWithRect:options:context:] 来绘制文本。尽管这两个方法性能不错,但仍旧需要放到后台线程进行以避免阻塞主线程。

常见的文本控件 (UILabel、UITextView 等),其排版和绘制都是在主线程进行的,当显示大量文本时,CPU 的压力会非常大。解决办法是利用TextKit或者是CoreText自定义文本控件。详见:YYText。

7、图片解码以及图像的绘制

当你用 UIImage 或 CGImageSource 的那几个方法创建图片时,图片数据并不会立刻解码。图片设置到 UIImageView 或者 CALayer.contents 中去,并且 CALayer 被提交到 GPU 前,CGImage 中的数据才会得到解码。这一步是发生在主线程的,并且不可避免。如果想要绕开这个机制,常见的做法是在后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap 直接创建图片。目前常见的网络图片库都自带这个功能。

个最常见的地方就是 [UIView drawRect:] 里面了。由于 CoreGraphic 方法通常都是线程安全的,所以图像的绘制可以很容易的放到后台线程进行。

8、文件系统的调用

NSFileManager获取一个目录获取文件信息,进行多次递归计算,stat几乎瞬间完成,NSFileManager耗时较长且消耗CPU。

GPU

GPU是一个专门为图形高并发计算而量身定做的处理单元,比CPU使用更少的电来完成工作并且GPU的浮点计算能力要超出CPU很多。

GPU的渲染性能要比CPU高效很多,同时对系统的负载和消耗也更低一些,所以在开发中,我们应该尽量让CPU负责主线程的UI调动,把图形显示相关的工作交给GPU来处理,当涉及到光栅化等一些工作时,CPU也会参与进来,这点在后面再详细描述。

相对于CPU来说,GPU能干的事情比较单一:接收提交的纹理(Texture)和顶点描述(三角形),应用变换(transform)、混合(合成)并渲染,然后输出到屏幕上。通常你所能看到的内容,主要也就是纹理(图片)和形状(三角模拟的矢量图形)两类。

GPU资源消耗原因以及解决办法:

1、纹理的渲染

当在较短时间显示大量图片时(比如 TableView 存在非常多的图片并且快速滑动时),CPU 占用率很低,GPU 占用非常高,界面仍然会掉帧。避免这种情况的方法只能是尽量减少在短时间内大量图片的显示,尽可能将多张图片合成为一张进行显示。

2、视图的混合(Blended)

视图结构过于复杂,混合的过程、会消耗很多 GPU 资源。为了减轻这种情况的 GPU 消耗,应用应当尽量减少视图数量和层次,并在不透明的视图里标明 opaque 属性以避免无用的 Alpha 通道合成。当然,这也可以用上面的方法,把多个视图预先渲染为一张图片来显示。

Blended Layers(视图混合):在同一个区域内,存在着多个有透明度的图层,那么GPU需要更多的计算,混合上下多个图层才能得出最终像素的RGB值。

Misaligned Images(像素对齐):逻辑像素(point)和 物理像素(pixel)无法相匹配;图片的size和显示图片的imageView的size(逻辑像素(point))不相等。

3、图形的生成

CALayer 的 border、圆角、阴影、遮罩(mask),CASharpLayer 的矢量图形显示,通常会触发离屏渲染(offscreen rendering),而离屏渲染通常发生在 GPU 中。可以尝试开启 CALayer.shouldRasterize 属性,但这会把原本离屏渲染的操作转嫁到 CPU 上去。

好的方法是使用图片遮罩等方法,避免使用圆角和隐形等。详细:iOS的离屏渲染

解决方案:

1、预先计算UI布局

获取数据之后,异步计算Cell高度以及各控件高度和位置,并储存在CellLayouModel中,当每次Cell需要高度以及内部布局的时候就可以直接调用,不需要进行重复计算。

2、使用自动缓存高度

iOS 8之后出现了UITableView通过约束自动计算高度,但是因为iOS对于约束的算法问题,会导致流畅性降低,FDTemplateLayoutCell很好的优化了这个问题。

3、异步绘制

Facebook的开源项目Texture(原AsyncDisplayKit),通过利用ASDisplayNode封装了CALayer,实现了异步绘制。

第三方微博客户端墨客的是现实,当滑动时,松开手指后,立刻计算出滑动停止时 Cell 的位置,并预先绘制那个位置附近的几个 Cell,而忽略当前滑动中的 Cell。但也有缺点,快速滑动的时候有可能会出现大量空白。

3、高效图片加载

SDWebImage-github

YYImage-github

4、预加载

列表当中,当滑动到一个可以设定的位置的时候,提前获取下载下一页的数据,并绘制UI。详见:https://zhuanlan.zhihu.com/p/23418800。

5、针对Blended Layers以及Misaligned Images

Blended Layers:

尽量少的使用具有透明色的图片

尽量多的将UI部件增加背景色

减少同一像素点进行过多的颜色计算

Misaligned Images:

现象:

洋红色:UIView的frame像素不对齐,即不能换算成整数像素值。

黄色:UIImageView的图片像素大小与其frame.size不对齐,图片发生了缩放造成。

解决:

尽量使用ceil(),保证没有小数的UI绘制

尽量不实用0.01f标记UITableView或者UICollectionView的header以及footer

网络上获取的图片没有@2x和@3x的区别,需要我们缩放图片到与UIImageView对应的尺寸,且缩放后的图片的scale和[UIScreen mainScreen].scale相等,再显示出来。

其他:

下面的情况或操作会引发离屏渲染:

  • 为图层设置遮罩(layer.mask)

  • 将图层的layer.masksToBounds / view.clipsToBounds属性设置为true

  • 将图层layer.allowsGroupOpacity属性设置为YES和layer.opacity小于1.0

  • 为图层设置阴影(layer.shadow *)。

  • 为图层设置layer.shouldRasterize=true

  • 具有layer.cornerRadius,layer.edgeAntialiasingMask,layer.allowsEdgeAntialiasing的图层

  • 文本(任何种类,包括UILabel,CATextLayer,Core Text等)。

  • 使用CGContext在drawRect :方法中绘制大部分情况下会导致离屏渲染,甚至仅仅是一个空的实现。

UIViewController各方法的调用顺序及功能

发表于 Aug 12 2017

UIViewController各方法的调用顺序及功能

1. -(instancetype)initWithNibName:bundle:

//这个方法是在controller的类在IB中创建,但是是通过Xcode实例化controller的时候调用的.
//一般情况下调用 init 方法或者调用 initWithNibName 方法的实例化UIViewController,不管调用哪个方法都会调用initWithNibName。
/
如果是通过调用initWithNibName:bundle指定nib文件名初始化的话,ViewController会根据此nib来创建View。如果name参数为nil,则ViewController会通过以下两个步骤找到与其关联的nib:
1)找跟ViewController类名一样的文件,例如MyViewController,则查找是否存在MyViewController.nib
2)如果ViewController的类名以“Controller”结尾,例如ViewController的类名是MyViewController,则查找是否存在MyView.nib;
/

-(instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

2. -(void)loadView

当访问 UIViewController 的 view 属性时,view 如果此时是 nil,那么 VC 会自动调用 loadView 方法来初始化一个 UIView 并赋值给 view 属性。如果没有重载 loadView 方法,则 UIViewController 会从 nib 或 StoryBoard 中查找默认的 loadView ,默认的 loadView 会返回一个空白的 UIView 对象。

此方法在控制器的 view 为 nil 的时候被调用。 此方法用于以编程的方式创建 view 的时候用到。loadView 是使用代码生成视图的时候,当视图第一次载入的时候调用的方法。用于使用(写)代码来实现控件。用于使用代码生成控件的函数

需要注意的是,在view初始化之前,不能先调用view的getter方法,否则将导致死循环(除非先调用了[supper loadView]);

3. -(void)viewDidLoad

如果 loadView 不能生成 UIViewController.view, 系统将会反复调用 loadView 及 viewDidLoad 方法, 并且最终调用 [super loadView] 方法返回 UIViewController.view。

当VC的view对象载入内存后调用,用于对view进行额外的初始化操作 。

4. -(void)viewWillAppear:(BOOL)animated

视图即将可见时调用(这个时候 supperView 还是 nil,即显示动画切换之前调用 )。默认情况下不执行任何操作。

这个方法中完成任何与视图显示相关的任务,例如改变视图方向、状态栏方向、视图显示样式等。

5. -(void)viewWillLayoutSubviews

view 即将布局其 Subviews。比如 view 的 bounds 改变了(例如状态栏从不显示到显示,视图方向变化),要调整 Subviews 的位置,在调整之前要做的一些工作就可以在该方法中实现。

6. -(void)viewDidLayoutSubviews

view 已经布局其 Subviews。比如 view 的 bounds 改变了(例如状态栏从不显示到显示,视图方向变化),已经调整 Subviews 的位置,在调整完成之后要做的一些工作就可以在该方法中实现。

7. -(void)viewDidAppear:(BOOL)animated

视图已完全过渡到屏幕上时调用。在这个方法中执行视图显示相关附件任务,如果重载了这个方法,必须在方法中调用 [supper
viewDidAppear]。

释放过程

8. -(void)viewWillDisappear:(BOOL)animated

view 即将从 superView 中移除且移除动画切换之前,此时还没有调用 removeFromSuperview。

9. -(void)viewDidDisappear:(BOOL)animated

view从superView中移除,移除动画切换之后调用,此时已调用removeFromSuperview。

10. -(void)didReceiveMemoryWarning

当系统的内存不足时,该方法会被调用,我们可以在该方法里释放掉部分暂时不用的资源。

11. -(void)dealloc

viewController 最后的清理工作,释放视图对象的引用和 viewController 所需数据结构。

总结

  • loadView (当访问UIViewController的view属性时)
  • viewDidLoad (加载视图时调用)
  • viewWillAppear (视图即将可见时调用)
  • viewDidAppear (视图即将加入窗口时调用)
  • viewWillLayoutSubviews (视图布局改变时调用,如:屏幕旋转)
  • viewDidLayoutSubviews 在以下情况下会被调用:
    • 1、init初始化不会触发layoutSubviews
    • 2、addSubview会触发layoutSubviews
    • 3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
    • 4、滚动一个UIScrollView会触发layoutSubviews
    • 5、旋转Screen会触发父UIView上的layoutSubviews事件
    • 6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件
      viewWillDisappear(视图将被从屏幕上移除之前调用)
      viewDidDisappear ( 视图已经被从屏幕上移除,用户看不到这个视图了调用)
  • 当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序
    • 1、alloc 创建对象,分配空间
    • 2、init (initWithNibName) 初始化对象,初始化数据
    • 3、loadView 从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
    • 4、viewDidLoad 载入完成,可以进行自定义数据以及动态创建其他控件
    • 5、viewWillAppear 视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
    • 6、viewDidAppear 视图已在屏幕上渲染完成
  • 当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反
    • 1、viewWillDisappear 视图将被从屏幕上移除之前执行
    • 2、viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
    • 3、dealloc 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

顶部导航栏

发表于 Aug 12 2017

简介

项目中经常会碰到顶部导航栏需要隐藏的情况,这里给出三种方法。

第一种

简单粗暴直接上来就隐藏掉导航栏,在基类中自己定义view充当导航栏的作用

第二种

1
2
3
4
5
6
7
8
9
10
11
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}

这里一定要用动画的方式隐藏导航栏,这样在使用滑动返回手势的时候效果最好,和上面动图一致.这样做有一个缺点就是在切换tabBar的时候有一个导航栏向上消失的动画。

第三种做法(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@interface HomePageController () <UINavigationControllerDelegate>
@end
@implementation HomePageController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置导航控制器的代理为self
self.navigationController.delegate = self;
}
#pragma mark - UINavigationControllerDelegate
// 将要显示控制器
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
// 判断要显示的控制器是否是自己
BOOL isShowHomePage = [viewController isKindOfClass:[self class]];
[self.navigationController setNavigationBarHidden:isShowHomePage animated:YES];
}
- (void)dealloc {
self.navigationController.delegate = nil;
}

注意(最后要记得在控制器销毁的时候把导航栏的代理设置为nil)

NSProcessInfo 获取进程信息

发表于 Jul 12 2017

NSProcessInfo 获取进程信息

###//返回当前进程的信息

1
+(NSProcessInfo*)processInfo

###//以NSString对象数组的形式返回当前进程的参数

1
-(NSArray*)arguments

 

###//返回变量/值对词典,以描述当前的环境变量(比如PATH和HOME)及其值

1
-(NSDictionary *)environment

 

###//返回进程标识符,它是操作系统赋予进程的唯一数字,用于识别每个正在运行的进程

1
-(int)processIdentifier

 

###//返回当前正在执行的进程名称

1
-(NSString*)processName

###//每次调用这个方法时,都返回不同的单值字符串,可以用这个字符串生成单值临时文件名

1
-(NSString *)globallyUniqueString

###//返回主机系统的名称

1
-(NSString *)hostname

###//返回表示操作系统的数字

1
-(NSUInteger)operatingSystem

###//返回操作系统的名称(可能返回的值定义在NSProgressInfo.h文件中)

1
-(NSString *)operatingSystemName

###//返回操作系统的当前版本

1
-(NSString *)operatingSystemVersionString

###//将当前进程名称设置为name。应该谨慎地使用这个方法,应为关于进程名称存在一些假设(比如用户默认的设置)

1
-(void)setProcessName:(NSString *)name

Xcode调试

发表于 Jun 12 2017

Xcode调试技巧

日志输出&LLDB

什么是LLDB呢:它是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器。LLDB 绑定在 Xcode 内部,存在于主窗口底部的控制台中。调试器允许你在程序运行的特定时暂停它,你可以查看变量的值,执行自定的指令,并且按照你所认为合适的步骤来操作程序的进展。我们可以简单的理解成它是一个调试器

1 命令行LLDB的出现

如下图,调试过程中程序运行到断点处时,控制台的右边会出 现“lldb”。

2 常用的命令

1 help
断点时,控制台输入”help“,回车,就能看到lldb命令及介绍
help
2 print
打印 常用p 代替
p
3 prin object
打印对象的详细信息 常用 po 代替
po
4 expression
可以在当前位置改变程序实际参数的值(不用重新运行项目) 使用过程中我们可以直接用 expr来代替expression。
expression
5 call
call
一般调用没有返回值的方法时使用call 例如 在viewDidLoad中断点,然后输入

1
call [self.view setBackgroundColor:[UIColor redColor]]

继续运行,view的背景就变成红色呢,很方便

6 image

mage list 查看工程中使用的库

image lookup –address 0x000000010e0979ac 程序崩溃的时候定位,查看具体报错位置 (不太好用)

断点

断点里面根据作用和功能也有很多种类:普通断点、条件断点、异常断点、符号断点等

普通断点

条件断点

打上断点之后,对断点进行编辑,设置相应过滤条件。单击右键会弹出选项框:

编辑断点

1
2
3
4
5
6
7
Edit BreakPoint... :编辑断点。
Disable  BreakPoint :断点失效。(相当于上边说到的单击断点变成浅蓝色,断点失效)
Delete BreakPoint :删除断点。
Reveal in BreakPoint Navigator :在左边的断点树状结构表明该断点。

Edit BreakPoint。这里面设置断点的筛选条件(双击断点也可以快速进入编辑断点的对话框)。

设置断点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
【1】Condition:返回一个布尔值,当布尔值为真触发断点,一般里面我们可以写一个表达式。
【2】Ignore:      忽略前N次断点,到N+1次再触发断点。
【3】Action:      断点触发事件,分为六种:
           <1>  AppleScript:执行脚本。
           <2>  Capture GPU Frame:用于OpenGL ES调试,捕获断点处GPU当前绘制帧。 
           <3>  Debugger Command:和控制台中输入LLDB调试命令一致。
           <4>  Log Message:输出自定义格式信息至控制台。
           <5>  Shell Command:接收命令文件及相应参数列表,Shell Command是异步执行的,只有勾选“Wait until done”才会等待Shell命令执行完在执行调试。
            <6>  Sound:断点触发时播放声音。
【4】Options(Automatically continue after evaluating actions选项):选中后,表示断点不会终止程序的运行。

异常断点 Exception Breakpoint(全局断点)

全局断点
同样的,全局断点也是可以编辑的,单击右键或者双击断点就会弹出编辑框,编辑的项目和上述是一样的。

符号断点 Symbolic Breakpoint

条件断点

4、监控断点

监控断点
我们调试程序的大部分时候都是为了监控某个变量的变化,在代码中变量出现的地方添加断点不仅累而且还可能漏掉,事后还得一个一个删掉,实在很累。
我们可以通过为变量添加监控断点来简单地做到这一点。找到变量第一次出现的地方,添加一个普通断点,进入 debug 模式后在 Variables View 中右键变量,选择 Watch 变量名。这样,每一次该变量被改变都会触发断点告知我们

更详细

.a静态库制作

发表于 Dec 20 2016

iOS开发之.a静态库制作

以Xcode8.2为例,简单封装图片界面等资源文件到.a静态库。

1.首先将资源文件打包成Bundle的模板

借助于OS X,因为iOS框架中没有创建Bundle的模板

删除工程中多余的文件

由于删除了plist文件,所以必须在Build Settings中删除对它的引用

我们创建项目时选的是OS X中的框架,所以此处需要修改Base SDK为iOS

设置完后,可以把我们需要的资源拷贝过来

按快捷键”Command + B”编译,编译成功后,Products下面的PictureOCRImage.bundle由红色变成了黑色,表示编译成功

可以通过右击 Show in Finder -> 查看文件夹 ->右击显示包内容,查看里面的内容

至此,资源打包成bundle完成.如果只是普通的资源,完全可以创建一个文件夹,把需要封装的资源文件拷贝至该目录下,将其改成后缀名为bundle即可,然后就可以使用NSBundle提供的接口访问其内部的资源文件,当然,也可以通过访问普通文件目录的方法访问其内部的资源。这样写主要是考虑到xib文件打包

2.制作.a文件库

新建项目,点击iOS—Framework&—Cocoa Touch Static Library。

系统自动生成以工程名命名的.h和.m文件,可自定义的在目录下添加或删除文件,注意目录下Products文件夹有一个.a文件为红色,说明文件并不存在。这里我们将系统生成的.h和.m文件删除。

将需要打包的文件添加到工程中

点击Build Phases—Copy Files,左下角点击+号按钮,添加你需要暴露的接口头文件。

点击左上角,选择Edit Scheme,Build Configuration下选择Release,先注意检查下面Release是否为NO:Yes表示只编译选中模拟器设备对应的架构,No则为编译所有模拟器设备支持的cup架构(Debug版本同理),选择NO,然后分别在模拟器和真机下Command+B编译一下,会看到Products文件夹下的.a文件变为黑色,这个.a文件就是我们想要得到的静态库。


可以通过右击 Show in Finder -> 查看文件夹,打开Build—Products文件夹,会看到Release-iphoneos和Release-iphonesimulator文件夹,分别是真机和模拟器的.a文件,为了使用方便我们将两个版本的.a文件合并。
合并真机和模拟器.a文件,在终端输入以下命令行:lipo -create 模拟器.a文件的路径 真机.a文件的路径 -output 合并后的保存路径(例:lipo -create /Users/dcd/Library/Developer/Xcode/DerivedData/TestCocoa_Touch-gjlcdmvelybrhdfbqwxscxvvtsqy/Build/Products/Debug-iphonesimulator/libTestCocoa\ Touch.a /Users/dcd/Library/Developer/Xcode/DerivedData/TestCocoa_Touch-gjlcdmvelybrhdfbqwxscxvvtsqy/Build/Products/Release-iphonesimulator/libTestCocoa\ Touch.a -output /Users/dcd/Desktop/TestCocoaTouch.a)最终会在桌面得到一个合并后的TestCocoaTouch.a文件,再将暴露出来的.h头文件一起复制出来


查看静态库.a对处理器架构的支持,先cd到.a文件的路径下,命令行输入:
lipo -info xxxxx.a

至此,.a库的制作完成了

参考文章:
http://www.cnblogs.com/richard-youth/p/4856841.html
http://www.fx114.net/qa-173-100870.aspx

知名博主

发表于 Aug 31 2016

最近空闲时间比较多,逛了写大牛的博客,收获良多

王巍 目前在日本横滨任职于LINE。工作内容主要进行Unity3D开发,8小时之外经常进行iOS/Mac开发。他的陈列柜中已有多款应用,其中番茄工作法工具非常棒。

池建强 70后程序员,Blogger。98年毕业,先后就职于洪恩软件、RocketSofeware和用友软件工程公司(后更名为瑞友科技),现任瑞友科技IT应用研究院副院长。该博客最初每天发送一条Mac技巧,不过目前已经形成了一种技术和人文结合的风格,时而随笔,时而技术。

许小帅 目前任职于腾讯,他还是iOS Feed站点的负责人。博客中对支付宝钱包插件分析的文章,引起了支付宝开发团队的反思,大家可以去感受一下。

萧宸宇 目前任职于Sumi Interactive。他出生于西南一个边陲小镇,梦想着能走出家乡,看看祖国的大好河山。他拥有丰富的 iOS 开发经验,在他的博客中发表了许多 iOS 开发的文章。

乔学士 目前任职于创业公司拓词,他正在为成为“代码手工艺人”而努力,目前主要进行 iOS 开发。最近他做得非常精彩的一件事就是汇总了WWDC 2013 视频英文字幕下载,大家可以前往他的博客感受一下。

破船 在移动领域摸爬滚打多年,经历了Symbian、Windows Mobile、Windows Phone和 iOS 等的洗礼。他希望能充分利用业余时间,努力做一名伪步道师。

骆仕恺 骆仕恺目前任职于爱折客 / 爱美味。他主要从事 iOS 和Java开发。拥有丰富的 iOS 开发经验。

耿健桓 目前在清华大学攻读硕士,之前他是著名站点知乎的 iOS 技术主管。

李择一 目前任职于百度,他在移动开发领域积累了丰富的经验,特别是 iOS 开发。最近他在博客中发表关于OC中block的追究非常有深度,大家一定要去感受一下。

王轲 是一名iOS独立开发者,也是IndieBros Studio创始人。在博客中有几篇关于 iOS 性能优化的文章,值得大家去看看。

连栩 目前工作在加拿大温哥华,运营着自己的公司 Beyondcow,他是一名 OSX、iOS 程序员同时也是用户体验,交互界面设计师。在开发的软件 Miao 是一款全功能 Mac 微博客户端。他的博客中有许多Cocoa开发的文章,值得大家去品读。

高嘉峻 目前任职于天猫。是一名资深80后,号称会写代码的猪。最近他的博客中出现了两篇关于iOS中单元测试的文章,非常棒。

webfrogs 目前在北京当一枚程序猿,有幸成为80后的尾巴。目前行走在iOS开发的道路上,用博客记载一路上的所见所闻所想。

景总 目前任职于天猫国际移动开发CTO,曾就职于平安科技项目经理,对IM和APP性能优化有深刻间接。

谭灏 目前就职于腾讯mac管家部门,他是一名 OSX、iOS 程序员,他的博客中有许多mac,ios开发的文章,值得大家去品读。

田伟宇 目前任职于天猫,全能人才。最近他的博客中出现了篇关于iOS应用架构详谈的文章,非常棒。

Markdown入门学习小结(常用语法)

发表于 Aug 17 2016

1.标题

Markdown语法:

1
2
3
4
5
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题

预览效果:

一级标题

二级标题

三级标题

四级标题

五级标题

2.粗体·斜体

Markdown语法:

1
2
3
4
**粗体**
__粗体__
*斜体*
_斜体_

预览效果:

粗体
粗体
斜体
斜体

3.分割线

Markdown语法:

1
2
3
---
***
~~文字删除线~~

预览效果:



文字删除线

4.列表

Markdown语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- 无序列表项目
- 无序列表项目
- 无序列表项目
* 无序列表项目
* 无序列表项目
* 无序列表项目
1. 有序列表项目
2. 有序列表项目
3. 有序列表项目
- 外层列表项目
+ 内层列表项目
+ 内层列表项目
+ 内层列表项目
- 外层列表项目

预览效果:

  • 无序列表项目
  • 无序列表项目
  • 无序列表项目
  • 无序列表项目
  • 无序列表项目
  • 无序列表项目
  1. 有序列表项目
  2. 有序列表项目
  3. 有序列表项目
  • 外层列表项目
    • 内层列表项目
    • 内层列表项目
    • 内层列表项目
  • 外层列表项目

5.添加超链接,图片

Markdown语法:

1
2
[百度](http://www.baidu.com)
![简书slogan](http://upload-images.jianshu.io/upload_images/103055-1854e79fc97374d1.png?imageView2/2/w/1240/q/100)

预览效果:

百度
简书slogan

6.添加表格

Markdown语法:

1
2
3
4
5
ABCD | EFGH | IGKL
-----|------|----
a | b | c
d | e | f
g | h | i

预览效果:

ABCD EFGH IGKL
a b c
d e f
g h i

7.引用

Markdown语法:

1
2
3
4
5
> 引用的文字引用的文字引用的文字引用的文字引用的文字
>> 引言内的引言引言内的引言引言内的引言
> 引用的文字引用的文字引用的文字引用的文字引用的文字

预览效果:

引用的文字引用的文字引用的文字引用的文字引用的文字

引言内的引言引言内的引言引言内的引言

引用的文字引用的文字引用的文字引用的文字引用的文字

8.添加脚注

Markdown语法:

1
2
A[^A]
[^A]: 注释的内容

预览效果:

A^A

9.创建链接

Markdown语法:

1
<test@test.com>

预览效果:

test@test.com

10.转义字符

Markdown语法:

1
2
3
4
5
6
7
8
9
10
11
12
\\
\`
\*
\_
\{\}
\[\]
\(\)
\#
\+
\-
\.
\!

预览效果:

\
`
*
_
{}
[]
()
#
+
-
.
!

11.引用

单行试

> hello world

预览效果

hellow world

多行式

> hello world
> hello world
> hello world
或者
> hello world
  hello world
  hello world

预览效果

hello world
hello world
hello world

hello world
hello world
hello world

多层嵌套

aaaaaaaaa

bbbbbbbbb

cccccccccc
预览效果
aaaaaaaaa
bbbbbbbbb
cccccccccc

12.行内标记

标记之外`hello world`标记之外

标记之外hello world标记之外

13.代码块

1
2
3
4
5
<div>
<div></div>
<div></div>
<div></div>
</div>
1
2
3
4
5
<div>
<div></div>
<div></div>
<div></div>
</div>

自定义语法

1
2
3
4
var num = 0;
for (var i = 0; i < 5; i++) {
num+=i;
}
1
2
3
4
var num = 0;
for (var i = 0; i < 5; i++) {
num+=i;
}

14.任务列表

注:兼容性一般 要隔开一行

 这是文字……
- [x] 选项一
- [ ] 选项二  
- [ ]  [选项3]
  • [x] 选项一
  • [ ] 选项二
  • [ ] [选项3]

为什么要写博客

发表于 Aug 12 2016

为什么写博客

一 我心中的博客

写博客是一个学习理解提升的过程。

1 自己了解学习,文章所涉及到的知识点,及知识点衍生出来的知识点。

2 对学习的知识点进行验证,以确保理论值与实践值保持一致

3 构思文章的大纲,哪些部分需要重点写,需要配合实例代码,图片等信息

4 动手写,写完后再次检查校正并排版,然后发表

5 针对网友的评论中提出的问题进行回复

二 为什么要写博客

2.1 为自己

写博客对自己的提升是很大的,可能写一篇体现不出来,但是只要你坚持写效果就很明显,好处人个认为有以下几点

2.1.1 强化知识点:在写一篇文章前,你必定是要把以文章中心为主的知识点及衍生的知识点都详细了解一 篇,在这一过程中必须会涉及到自己以前所了解过的知识,人的记忆是存在记忆曲线的需要不断的重复记忆才能长久的记住某一事物,而每写一篇文章时都会查阅资 料,在这一过程中必然会遇到以前记住了而现在渐渐淡忘的知识点,当你再次看到时瞬间就会回想起,此时以前的知识点就得到了强化。

2.1.2 提升学习能力:同一样的人,了解同一知识点,用不同的方 法,产生的结果必然会不一样,找到最佳的学习方法,这也是一种能力,这种能力是经过多次实践探索之后总结出来的,以前我每次需了解某一种技术时都会先百度 看各种搜索结果,发现没有想要的之后,再Google因为Google的结果与百度的会有所不同,Google结果中国外的文章相对会多一点,而偶然点了 一个链接进入了博客园,发现就是自己想要的东西,而且把概念,代码,及经验都写上去了,看完之后对我帮助很大。渐渐的我便开始采这种方法了解新知识概念性的直接看百度百科,实质性的直接 上博客园的 找找看 ,群里的朋友还推荐了一种方法,比如我要学MVC 园子里很多人都写了 关于MVC的一系列文章,把那一系列的文章都看一遍,对于MVC就基本有了了解了,这便是学习能力的提升,对于某种技术用最短的时间做到了比较全面的了解

2.1.3 提升文字组织能力:这个就不用说了,写博客,既然是写,就必然会有大量的文字,而如何组织文字表达出自己想表达的意思,是长期练习的,而写博客正好帮助你提高了你的文字组织能力,

2.1.4 提升逻辑思维能力:不用说,技术性的东西从来就没的单独存 在的,都一层层技术相结合,那在了解某种技术时,自己的思维也是要顺着这种关系逐渐深入的,比如MVC,你不能只知道 M是什么V是什么 C是什么就行了吧,你得知道 M V C 这三者关系是怎样的,又是怎样交互,而你了解之后再把它写出来时,需要清晰逻辑。

2.2 为他人

2.2.1 有意的: 园子里有很多人都写过关于 MVC 框架 WCF 等等系列文章,目的就在于帮助新人快速上手,这个我深有体会,当初我开始学习MVC时就是看的T2噬菌体的MVC系  列文章,整篇看完后再配合自己动手对于MVC就有了基本的了解了,在次感谢园子里无私献的大牛们。而以上行为就是有意的帮助

2.2.2 无意的:很多时候在开发项目的过程中,遇到了技术问题,花了时间解决后,有人会写博客记录,并附上解决方法旨在当再次遇到问题时直接看下文章就知道如何处理了,而碰巧的是,这种问题不止他一个人遇到了。很多人在开发时也遇到了这个问题,在网上找答案时,就找到了这篇文章,并根据文章提供的解决方法,顺利的解决了问题,这种帮助就是无意的帮助

三 总结

我所认的写博客是对自己所了解知识的强化,分享,自身能力的提升。当然 写 博客只是一种方法而以,只要能达到提升自我的效果什么方法都是可以的,有些事情你现在不去做,可能以后都不会有机会了!

123
chuandong ding

chuandong ding

iOS

22 日志
2 标签
GitHub Twitter Weibo
Links
  • slarker
  • 大神
© 2019 chuandong ding
由 Hexo 强力驱动
主题 - NexT.Pisces