Swifter4

  1. Curring(柯里化)

    把接受多个参数的方法变换成接受第一个参数的方法,并且返回接受余下的参数并返回结果的新方法。

    在Swift2中可以将方法进行Curring 但是在Swift4不再支持方法的柯里化

    屏幕快照 2019-02-12 下午3.48.34

  2. @autoclosure

    func logIfTrue(predicate: () -> Bool) {
            if predicate() {
    print("true")
    }
    }
    调用方式1
    logIfTrue(predicate: {2 > 1})
    调用方式2
    logIfTrue{2 > 1}

    原来的闭包的书写方式如上面所写,但是看起来不是很容易理解,这时就出现了自动闭包。

    swift4 中的自动闭包书写和 swift2中不同 区别点在@autoclosure的位置,swift2中是在参数之前,在 swift4中是在参数之后。

    func logIfTrue(predicate:@autoclosure () -> Bool) {
            if predicate() {
    print("true")
    }
    }
    logIfTrue(predicate: 2 > 1)

    另外需要注意@autoclosure 并不支持带有输入参数的写法,只有形如()-> T 的参数才能使用这个特性进行简化。

  3. Designated、Convenience 和Required

    只有在子类重写了父类的 designated 方法的时候才可以直接调用父类的 convenience 方法

    如果添加 required 关键字修饰初始化方法,则在子类中必须对该 required 方法进行实现。这样做的好处就是可以保证依赖于某个 designated 方法的 convenience 一直可以被使用。

  4. Swift 中的Array,Dictionary和Set在集合中只能存储同一个类型的元素,但是NSArray可以存储多种不同类型的数据,如果想要Array 存储不同类型的数据,可以使用Any AnyObject

    let store:[Any] = [1,"1"]

2019/10/10 posted in  iOS

UINavigationItem

纵观Apple的官方应用程式的导航栏你就会发现在iOS11之后导航栏的高度会自动变化,文字的大小以及位置也会随之变化。
这是iOS11之后的新特性,苹果是使用给UINavigationItem添加扩展的方法增加的新功能,这也给了我们新的一种思路,为了不去修改之前代码的原则上添加新的功能的方式。

extension UINavigationItem {
    public enum LargeTitleDisplayMode : Int {
        /// Automatically use the large out-of-line title based on the state of the previous item in the navigation bar. An item with largeTitleDisplayMode=Automatic will show or hide the large title based on the request of the previous navigation item. If the first item pushed is set to Automatic, then it will show the large title if the navigation bar has prefersLargeTitles=YES.
        case automatic

        
        /// Always use a larger title when this item is top most.
        case always

        
        /// Never use a larger title when this item is top most.
        case never
    }
}
  • largeTitie的两种展现形式如下所示

屏幕快照 2018-12-05 下午1.23.25 屏幕快照 2018-12-05 下午1.23.29

设置方式

  • xib设置

    • never 一直都是小标题
    • automatic 自动切换
    • always 一直都是大标题

屏幕快照 2018-12-05 下午1.30.58

  • 代码设置

    因为这是新增加的属性所以要做判断
     if #available(iOS 11.0, *) {
    self.navigationItem.largeTitleDisplayMode = .automatic
    } else {
    // Fallback on earlier versions
    };
2019/9/11 posted in  iOS

Love at First Launch

  • 直接显示内容而不是弹出需要注册登录的页面
  • 通过交互引导用户,而不是一些文字引导
  • 延迟请求授权,而不是一下登录之后就开始要权限(定位,相机,图片)。

针对延迟请求,想到一个好主意,就是新建一个类,可以是单例,负责管理这些请求。

App Startup Time: Past, Present, and Future

了解在苹果平台上使用的dyld动态链接器,它是如何在这些年来发生变化的,以及它下一步的发展方向。了解改进的工具如何使优化应用程序的启动时间变得更容易,并了解dyld中的新更改如何进一步改善启动时间。

  • startup time 启动时间

    main函数执行之前所用的时间

  • launch closure启动收尾

    启动你的程序所需要的全部信息,比如使用什么dylib,他们的哪些偏移位置用于不同的符号,代码签名是什么,

Improving App Startup Time

Do less!

  • Ember fewer dylibs
  • Declear fewer classes/methods
  • Use fewer initializers

减少代码,代码越少,启动速度越快。使用更少的dylib,减少嵌入的dylib,使用系统库效果会更好。应该声明较少的库和方法,减少初始化函数( 初始化函数是在main函数执行之前执行 )。

Use more Swift

  • No initializers
  • Swift size improvements

因为Swift从设计上避免了许多的陷阱,在c、c+++、oc可能遇到这些陷阱。
Swift没有初始化器,不允许特定类型的未对齐的数据结构。所以转向Swift可以让你更容易获得快速的程序启动(Apple says)。

Static initilizer tracing

静态初始化追踪器,instrument提供每个静态初始化器的准确时间。方便知道初始化的过程花费了多久的时间。

屏幕快照 2018-12-11 下午3.33.52

dyld3

为什么推出dylb3

提升速度(启动应用的时候尽量多的减少工程量)
增强安全(更积极的安全检查)
可测试性和可靠性

怎么做到上述目标

  • 速度

    • 把复杂操作dylb移出进程

      • 现在大多数dylb只是普通的后台程序
    • 允许部分dylb驻留在进程之中

      • 减少受攻击面积(驻留部分要尽可能少)
      • 提高启动速度
        • 最快的代码就是你不写代码
        • 关注那些你几乎不执行的代码
  • 安全

    • 确定安全敏感性组件身份

      • 边界检查
      • @rpath 攻击
    • 标识可占用缓存的组件

      • 依赖关系不会改变
      • 符号在库中的偏移位置不会发生改变

屏幕快照 2018-12-11 下午5.36.31

dylb3有三个部分

  • 一个进程外的macho 解析编译器
  • 一个进程内的处理闭包(launch closures)的引擎
  • 一个缓存服务的启动闭包(launch closures)

大多数启动的时候使用缓存不会触发进程外的mach-o parser/compiler
launch closures比mach-o更简单
launch closures为速度而构建

使用dylb3要注意什么

完全兼容dylb2.x

  • 一些apis关闭了dylb3的优化导致程序变慢或者会在dylb3中使用回退模式
  • 一些为dylb2.x的优化不再有任何影响

严格的链接语义
在加入新动态连接器后,很多的语义可能现在还无法使用,甚至是错误的。

  • 放入一个支持旧二进制数据的工作区
  • 新的二进制数据可能导致链接错误
2019/9/11 posted in  iOS

Advanced Debugging with Xcode and LLDB

  1. expression语句

    不用重新运行程序直接实现代码效果

    1. 描述

      可以动态的改变条件,语法是expression xxx = "xxx" 后面是语句代码,类似程序中的代码并且支持加{}的判断等等语句。

    2. 使用方法:

      • 调试台去写这个语句
      • 加断点去添加action
  2. Symbolic Breakpoint

    1. 描述

      符号断点,可以针对某一个方法(函数)设置断点并暂停执行;有时候,我们并不清楚会在什么情况下调用某一个函数,那我们可以通过符号断点来跟踪获取调用该函数的程序堆栈。

      屏幕快照 2018-12-10 下午5.04.43

    2. 使用方法

      • 方法一

      添加符号断点,比如如下所述-[UILabel setText:]

      屏幕快照 2018-12-10 下午5.05.33

      还可以添加condition语句 类似如上所述

      • 方法二

      直接在指定的语句添加断点加入action语句,如图所示

      breakpoint set --one-shot true --name "-[UILabel setText:]"

      one-shot 是一个临时断点,一旦触发后就自动删除

  3. 跳过断点所指向的代码

    1. 方式一

      屏幕快照 2018-12-10 下午5.40.21

      移动手柄实现 接下来就可以在控制台中写expression语句
      expression jumpAstronaut(animated:false)

    2. 方式二

      直接编辑断点添加action语句
      屏幕快照 2018-12-10 下午5.47.11

      thread jump --by 1 是跳过一句代码的意思。

  4. watchPoint

    观察指针,值发生改变的时候自动暂停。

    右键某个属性,添加watchPoint,然后左侧会出现观察指针断点监测_tableView的变化,如下所示

    屏幕快照 2018-12-11 上午11.46.38

  5. 创建别名

    command alias poc expression - l objc -O --
    poc 就可以直接代替后面的语句,可以简化常用的命令行语句。

  6. 可以通过内存地址去获取对象

    1. Objective-C

      po 指针 可以直接打印出对象
      屏幕快照 2018-12-11 上午11.12.11

    2. Swift

      不能把数字当成指针去像OC一样打印出对象,要使用expression - l objc -O -- 0x7fa967d781191548b60转换为OC语言。 如果觉得这个语句太臃肿,可以为语句创建别名比如command alias poc expression - l objc -O --之后就可以直接poc 指针就可以达到oc当中同样的效果。

  7. 获取图层树

    1. Objective-C

      调用po [self.view recursiveDescription]打印出类似于这样的图层树。

    2. Swift

      不能这么直接打印出图层树(swift不允许去调用未定义的函数),如果要让swift去像OC一样打印出类似于这样的图层树。
      调用语句

      ```一定要加入反括号(反括号就像预处理器一样,它表示先评估其在当前帧中的内容,并插入结果,然后我们可以评估其余部分) 才能编译通过。
      
  8. unsafeBitCast查询对象的调试描述

    当只有指针,查看对象描述的时候在swift中可以使用 unsafeBitCast函数,给他一个内存地址,他不安全是因为它依赖你来提供正确的类型。

    po unsafeBitCast(指针,to:ScoreBoardView.self)
    还可以可以直接查看view的frame
    po unsafeBitCast(指针,to:ScoreBoardView.self).frame

    同理OC中可以更方便的实现根据指针对对象进行相应的调试,比如更改 label 的内容

    (lldb) expression [(UILabel*)0x7fb2c5f0fd70 setText:@"hello"];
    但是内存地址前面要跟相应的类型要不然会执行失败报错
    error: warning: receiver type 'long' is not 'id' or interface pointer, consider casting it to 'id'
  9. 刷新屏幕的帧缓存区
    如果写了expression语句之后界面没有及时刷新,但是又不想去重新运行代码,那么可以使用表达式
    Swiftexpression CATransaction.flush()
    OCexpression [CATransaction flush]刷新屏幕帧缓存区。

参考

[1]https://developer.apple.com/videos/play/wwdc2018/412/

2019/9/9 posted in  iOS

检测离屏渲染

instrumets 已经取消了debug options

可以在xcode的debug - view debugging 找到

“核心动画工具和模板已在工具中弃用。之前在”调试选项“下的功能已移至Xcode,位于”Debug> View Debugging“下。

BB55F33F-97CC-4C28-B3F1-22456A2A7BD8.png

开启后会把那些需要离屏渲染的图层高亮成黄色,这就意味着黄色图层可能存在性能问题。

正常:是这样的
正常渲染.png

有问题的图层:

调试.png
可以看见我设置了圆角的imageView有问题.

### 项目开发中怎么去处理?

抛出一个问题: 需求就是有很多圆角那我们项目中应该怎么去处理圆角呢?

  1. 使用YYWebImage去处理
  2. iOS中圆角图片的处理

相信看完两篇文章,多少都会能收获一点!

有些人说:

iOS 9.0 之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了,如果设置其他阴影效果之类的还是会触发离屏渲染的(这句话不知道谁说的.自己有没有去尝试呢???)

结论: 经过测试

70915C7C-7523-4008-9A88-B5682407926D.png

大家可以看到,
UIButton 的 masksToBounds = YES下发生离屏渲染与 背景图存不存在有关系, 如果没有给按钮设置 btn.image = [UIImage imageName:@"xxxxx"]; 是不会产生离屏渲染的 .

关于 UIImageView,现在测试发现(现版本: iOS10),在性能的范围之内,给UIImageView设置圆角是不会触发离屏渲染的,但是同时给UIImageView设置背景色则肯定会触发.触发离屏渲染跟 png.jpg格式并无关联(可能采取的压缩格式不同,这里不做探讨,这里我给出结果是没有关系)

2019/8/15 posted in  iOS

七号房的礼物

要怎么才能好好的挥手道别呢,最后的时候爸爸觉得自己再也见不到自己女儿那一刻,害怕了。但是没有人能再救他回来,影片最后真的让人声泪俱下。

父女之间的爱情,狱友之间的帮助,可能多少美化了一部分,但是人的内心深处总留有那么一块正义时刻吧,由于匆忙结案酿成了一场冤假错案,如何对抗一个体制,看得实在揪心,总希望这样的事情不会发生,最后的结局可能是一种对于现实的妥协,给影片画上了一个句号,还了龙九的清白,其实如果放到现实中,恐怕这样接近圆满的结局会很困难吧。

到底真相是什么我们不得而知,但是我们知道龙九是被冤枉的没错。

2019/7/20 posted in  电影

_cmd 与 runtime 的结合

只有运行时给分类添加属性,大部分都是这样的

- (NSString *)customName {
     return objc_getAssociatedObject(self, &kExtendVarKey);
   }
- (void)setCustomName:(NSString *)customName {
    objc_setAssociatedObject(self, &kExtendVarKey,, customDelegate, OBJC_ASSOCIATION_RETAIN_COPY);
 }

_cmd 是隐藏的参数,表示当前方法的selector,另外隐藏参数self表示当前方法调用的对象实例。
这个参数是唯一的参数,在一个文件中方法名不会重复。
所以可以让它代替运行时当中的属性的键名。

- (NSString *)customName {
     return objc_getAssociatedObject(self, _cmd);
   }
- (void)setCustomName:(NSString *)customName {
    objc_setAssociatedObject(self, @selector(customName), customName, OBJC_ASSOCIATION_RETAIN_COPY);
  }
2019/7/15 posted in  iOS

高效的画线

先创建一个UIBeizerPath 的对象path

UIBezierPath *path = [[UIBezierPath alloc] init];
  [path moveToPoint:CGPointMake(175, 100)];
  
  [path addArcWithCenter:CGPointMake(150, 100) radius:25 startAngle:0 endAngle:2*M_PI clockwise:YES];
  [path moveToPoint:CGPointMake(150, 125)];
  [path addLineToPoint:CGPointMake(150, 175)];
  [path addLineToPoint:CGPointMake(125, 225)];
  [path moveToPoint:CGPointMake(150, 175)];
  [path addLineToPoint:CGPointMake(175, 225)];
  [path moveToPoint:CGPointMake(100, 150)];
  [path addLineToPoint:CGPointMake(200, 150)];

然后创建CAShapeLayer添加到视图的layer上

CAShapeLayer *shapeLayer = [CAShapeLayer layer];
  shapeLayer.strokeColor = [UIColor redColor].CGColor;
  shapeLayer.fillColor = [UIColor clearColor].CGColor;
  shapeLayer.lineWidth = 5;
  shapeLayer.lineJoin = kCALineJoinRound;
  shapeLayer.lineCap = kCALineCapRound;
  shapeLayer.path = path.CGPath;
  //add it to our view
  [self.containerView.layer addSublayer:shapeLayer];
2019/5/11 posted in  iOS