Sucha's Blog ~ Archive for March, 2015

15年3月30日 周一 15:10

升级 Yosemite

完全就是一次被迫升级。

事情的开端在于好奇心升级了 iPad Air 到 iOS 8.2,然后有个 APP 要调,偏偏 Xcode 6.1 的 SDK 不支持 iOS 8.2,然后又是好奇心,下载了个 Xcode 6.3 beta 2,周日下了整整一天呀,宿舍里宅人太多了,各种抢带宽。

到了凌晨才下载完,安装后显示需要 10.10 才能跑,无可奈何。

于是不关机了,通宵 App Store 下载 10.10,我之前升级到 10.9.5 从变色龙到 Clover,用的是懒人版,其实很多安装设置我是不懂的,我只晓得 i3 2120 + H61 跑黑苹果没啥问题而已。

也许 Clover 版本太旧吧,开始安装 10.10 后一直卡在全屏白光,光标变光盘状 不动。

于是重启进入老系统 10.9.5,下了个 Clover 安装,看了一些小道消息,只是拷 贝了 EFI 下的 BOOT 和 CLOVER,其实真正的做法是保留 config.plist 用来参考, 安装 Clover 到系统盘,再配置就好。再原先错误的方式下,系统起不来了,BIOS 后显示插入 media。

手头的 SD 读卡器 + 8G SD 卡这个 H61 主板不认,没法当成启动盘,那个 320G 的 USB 硬盘也不可以。

我差点忘了手头还有一个前几天面试某公司人家当礼物送的 U 盘,现在马上用上 当成系统救急盘了。

将 07 年购入的双系统老笔记本启动到 win7 热身,在 U 盘上装了 Clover 启动 了 10.9.5,重新安装新版 Clover 继续 10.10 的安装,然后启动。

已经是下午 3 点了,折腾。

第一眼的感觉,就是进入系统后感觉扁平化的视觉不如之前的 10.9.5 的好看,其 他方面还没弄,一些软件不兼容,报告的有 VMware 的一些 kext,这个有点蛋疼, 估计要把这个 VMware 给去掉了,以后用那台双系统老机子跑 win7 好了。

15年3月7日 周六 23:41

[iOS] 被逼的 VFL

把几年前的 app demo 搬出来,当年还没有 5、5s、6、6p 的时候,界面的布局是 简单的,可是这两年 duang 一下出来了这么多新机器,现在 iOS 下屏幕分辨率的 分裂程度也是让人目瞪口呆。

当年一个控件 xib 就可以横行天下,5、5s 出来后有些控件不得不加了一个 xib, 6、6p 出来后,我想我有时是拒绝使用 xib 了,妹的 6 跟 6p 的分辨率都没什么 关联嘛。

官方的说法 5、5s、6 都是 2x,6p 是 3x,并且为动态的控件还加了 autosize, 可这玩意儿我不懂用。

学着在 xib 里面使用 constraints,总是达不到自己想要的效果,折腾了好久好 久,腰酸背痛是真的。

看了一下官方那一页 VFL,第一次感觉到不知所云。于是上 github 找替代品,比 如 PureLayout,用了一下,使用上有些限制,且效果仍然不是我想要的。

说一下我要的效果,table view cell 里面放多张方形图片,portrait 跟 landscape 下布局不一样,前者是

space | image | space | image | fixed space

后者是三个 image,而且我还考虑 6p 下面多加一个 image。如果我选择 xib,不 是累死。

即便 PureLayout,还需要我指定中间间隔 space 的宽度,可我想这不是需要动态 计算的吗,如果我能知道这个宽度的值,我都可以自己计算 frame 的大小咯,还 要constraints 干嘛,我都 specify 了。

我不明白的是,当年 CSS 都可以指定某个标签具体位置的百分比,方位,为啥水 果的 VFL 不行呢,看起来 PureLayout 也不好使呀,比如第三个例子,我想要的 效果还有距离。

于是又 baidu、bing VFL 的资料,官网又硬着头皮看了一下,终于有点开窍了, 后来发现其实 VFL 是简单的。

它的基础是所有需要动态伸缩的东西,都是一个 UIView(我是这么理解的),所 有的数值,都是固定的,要么是间隔,要么是相互关系,比如宽是高的两倍。

这就清楚了,其实官方 VFL 里面的 Spacing and Wrapping 举的例子就很清晰了, 我上面要的效果里面,space 都是 UIView,动态计算就好。

指定三个 image 宽、高相等,三个 image 的宽都相等,多个 space 的宽都相等, 然后在指定 image 的高度(Y值)就足够了,后面 fix space 就不需要一个 UIView 了,可以直接指定了。

相比之下,感觉到是 IB 里面的 constraits 反而操作复杂了,而且经常是说限制 不够,运行又出错什么的。

可是明明二维的坐标,x、y 可以确定的话,那个东西就固定了呀,IB 会有让我找 不着北的感觉,且里面的 constraints 也不容易看出来,太乱。

相比之下 VFL 就好很多,只是概念不好说清,比如那个 space,我是先入为主, 觉得为啥不能像 CSS 一样,直接指定 UIView 的位置呢,谁能想到即便官方的文 档里面,需要动态计算大小的元素,只能是 UIView。

写了一点 VFL 后,github 上又找了 Auto Layout Shorthand,但貌似不是完全的 映射,它自己封装了一些东西,只能作罢。

所以我也简单封装了自己的一些东西,试用了一个小时,感觉还不错,也放到 gist 上面 了。

// formula as 'width == width'
static NSLayoutConstraint*
_lcItemRel(UIView *v1, NSString *formula, UIView *v2, float ratio, float constant) {
    static NSDictionary *attrValueForName = nil;
    static dispatch_once_t attrOnceToken;
    dispatch_once(&attrOnceToken, ^{
        attrValueForName =
        @{
          @"left":      @(NSLayoutAttributeLeft),
          @"right":     @(NSLayoutAttributeRight),
          @"top":       @(NSLayoutAttributeTop),
          @"bottom":    @(NSLayoutAttributeBottom),
          @"leading":   @(NSLayoutAttributeLeading),
          @"trailing":  @(NSLayoutAttributeTrailing),
          @"width":     @(NSLayoutAttributeWidth),
          @"height":    @(NSLayoutAttributeHeight),
          @"centerX":   @(NSLayoutAttributeCenterX),
          @"centerY":   @(NSLayoutAttributeCenterY),
          @"baseline":  @(NSLayoutAttributeBaseline),
          };
    });
    
    static NSDictionary *relationValueForName = nil;
    static dispatch_once_t relationOnceToken;
    dispatch_once(&relationOnceToken, ^{
        relationValueForName =
        @{
          @"==":  @(NSLayoutRelationEqual),
          @">=":  @(NSLayoutRelationGreaterThanOrEqual),
          @"<=":  @(NSLayoutRelationLessThanOrEqual),
          };
    });
    
    NSArray *kv = [formula componentsSeparatedByString:@" "];
    
    NSLayoutAttribute a1, a2;
    NSLayoutRelation r;
    
    if (kv[0]==nil || kv[1]==nil || kv[2]==nil) {
        return nil;
    }
    
    a1 = (NSLayoutAttribute)[((NSNumber*)attrValueForName[kv[0]]) integerValue];
    a2 = (NSLayoutAttribute)[((NSNumber*)attrValueForName[kv[2]]) integerValue];
    r = (NSLayoutRelation)[((NSNumber*)relationValueForName[kv[1]]) integerValue];

    return [NSLayoutConstraint constraintWithItem:v1
                                        attribute:a1
                                        relatedBy:r
                                           toItem:v2
                                        attribute:a2
                                       multiplier:ratio
                                         constant:constant];
}

static NSArray*
_lcAryOfVFL(NSString *formula, NSLayoutFormatOptions opt, NSDictionary *metric, NSDictionary *views) {
    return [NSLayoutConstraint
            constraintsWithVisualFormat:formula
            options:opt
            metrics:metric
            views:views];
}

gist 地址,https://gist.github.com/lalawue/430102f68327fe302964, 请自备 梯子。(最后又发现了个不错的 FLKAutoLayout,不过没用过,具体就不知道了)

15年3月7日 周六 23:22

播放器使用 OpenAL 需要注意的

扯一下写在线视频播放器使用 OpenAL 遇到过的坑吧。

由于不涉及到 listener 的位置与加速度,openal 参数的设置是简单的,且仅仅 只需要一个 source,一定量的 buffer,加上 streaming 的操作。

第一个问题来了,streaming 的操作,多个 buffer,可具体需要多少个呢,这个 还真不好说。我做过一些边界测试,不过没那么详细,iOS 真机还是模拟器上面, 总共可以开到 512 个 buffer name,这个数量总该够了吧。

或者,buffer 固定数量,自己先缓存一定量再扔进去,这样就解决了 buffer name 不够的问题。我这边播放 1M 多的码流,每个 audio packet 大概 8k,可以 算出来自己需要缓存多少时间。

第二个问题,其实是 OpenAL 默认的情况,就是 queue 上去的 buffer,播放完毕, 到达 stop 的状态后,新的 buffer queue 进来,其实仍然是 queue 到这些 buffer 的后面去,一旦设置成 play 状态,会先播放一遍已经 stop 的旧数据。

这个 bug 瞒了我很久,因为我之前的 seek 有些问题,加上 audio cache 又不多, 现象不明显。

这意味每次 queue 新的 buffer 进去之前,把里面的 processed buffer 都给 unqueue 先才行,这绝壁是个坑啊,哪有 stop 后还赖着不走的。

第三个问题,processed 后的 buffer name,其实在 C 的操作里面,不好存到已 有的 buffer 数组里面,得新开一个 free_buffer name 的数组,来存放已经 processed 的 buffer name,要不然这些 buffer name 会丢失,再想扔新的数据 时就找不到它了。

如果无论如何都先 queue 完已申请的 buffer name,然后再取 processed 的,就 能避免这个问题。可这又溶于遇到第二个问题,我就是这么绕进去的。

典型的 API 足够简单,但是使用小别扭的问题。OpenAL 我是参考了 1.1 的 specification,对于写视频播放器足够了,iOS 上官方说是低阶 API,性能足够, 且又跨平台,何求?