针对含有sub-project的project, 在依赖关系正确设置(关于如何正确设置, 参考本文最后提供的链接)的情况下, 如果直接用下面命令, 基本上编译会出错, 提示找不到sub-project里面的头文件:

xcodebuild -target TestApp -configuration Release clean build

这个命令会在当前目录下创建一个build文件夹, 然后将编译的中间产物和结果放进去, 而Xcode GUI在编译时是将这些放到DerivedData下面, 这一区别导致了在编译时找不到sub-project包含的一些东西.

解决方法很简单, 加上-scheme, 命令如下:

xcodebuild -scheme TestApp -target TestApp -configuration Release clean build

指定了-scheme之后, 命令行编译的行为就跟在Xcode GUI下编译一样了.

如果使用添加header search path的方法, 也能让编译通过, 但其实不是最正确的方法, 因为在GUI下编译不需要这一步.

如何正确设置sub-projct, 及本文参考见这里

Tagged with:  

Objective-C代码格式整理

On 04/07/2014, in iDev, iOS Dev, Mac Dev, by ultragtx

团队合作中代码风格一致比较重要, 像Google NewYorkTimes这些公司都公开了各自的Objective-C代码风格, 有需要的搜索一下就可以找到, 这里主要介绍借助Uncrustify自动整理代码格式的一些技巧.

Uncrustify: Source Code Beautifier for C, C++, C#, ObjectiveC, D, Java, Pawn and VALA, 篇幅及时间有限, 没必要过多介绍, 总之是一款定制性很高的代码格式整理工具, 但高定制性意味着配置起来很烦, 所以这里推荐一个开源图形界面配置文件编辑器UncrustifyX, 这个工具对各个配置都有详细的说明, 并且有直观的预览功能, 可以较为方便地编辑出你需要的配置, 当然更方便的方式是直接搜索别人写好的配置文件, UncrustifyX本身就带一个.

其他的关于如何安装, 如何更方便地在Xcode中使用, 可以参考这篇. 本文不再详细说明.

最后要说一下Uncrustify的一个缺点(Feature):Xcode会自动对代码中的空行添加空格缩进, 这样会对编辑代码带来方便, 而Uncrustify会删除所有行尾多余的空格, 这就意味着如果你用Uncrustify对一个已有的代码进行处理, 所有的空行缩进都会被删除, 产生大量无意义的diff, 同时影响下次编辑. 如果你期待可以通过配置文件来改变这个行为, 那恐怕就要失望了, 而且Uncrustify的作者基本上也明确表示了不会添加这个功能(现在有个issue, 里面有几个人在求这个功能).

这里提供一个简单技巧, 轻松解决这一问题, 在Xcode中, 我们可以通过全选代码, Move Line up(option+command+[) + Move Line Down(option+command+]), 来自动添加回那些消失的空格, 上面说的那个问题也就迎刃而解了. 另外说一下, AppCode自带的代码格式整理, 估计也是用Uncrustify实现的, 所以跟Uncrustify一个毛病.

–以上–

Tagged with:  

UIScrollView及其子类UITableView, UICollectionView为iOS开发带来了极大的方便, 其分页(pagingEnabled)功能也很常用, 但是功能却有些局限, 页只能按UIScrollviewbounds尺寸划分, 如果要实现自定义分页宽度或高度就需要一些技巧.

方法一

类似iOS 6中MobileSafari, 如图所示的分页方法:

HGPageScrollView_Screen_shot_2

 

StackOverflow上提供的实现思路如下:

 

  1. UIScrollviewbounds限制再屏幕中间那一页的位置
  2. 禁用UIScrollviewclipsToBouds, 从而能显示超出bounds的内容

此时已经可以在借助UIScrollview原有分页功能的基础上实现了"视觉上"与MobileSafari类似的效果, 但因为UIScrollview的尺寸限制, 超出范围的触摸事件不会被UIScrollview收到, 影响体验, 要把触摸事件传递给UIScrollview, 方法如下:

  1. 用一个全屏的(或者其他你想要的尺寸)UIView子类, 这里我们命名为CustomUIView来做UIScrollviewsuperView
  2. 重写CustomUIViewhitTest:withEvent方法:

     - (UIView *) hitTest:(CGPoint) point withEvent:(UIEvent *)event {
       if ([self pointInside:point withEvent:event]) {
         return scrollView;
       }
       return nil;
     }
    

    通过重写hitTest, 就可以将CustomUIView接受到的触摸事件传递给UIScrollView

方法二

前一种方法保留了UIScrollView原有的分页功能, 而下面这种更加灵活的自定义分页方法则完全自制了一个分页功能:

DMPagingScrollView就是一个很好的实现, 其自定义分页的思路大致如下(需要参考DMPagingScrollView.m代码):

  1. 用实例变量pageWidth记录自定义分页的宽度
  2. 通过实现UIScrollView的delegate方法, 来记录每次拖动UIScrollView动作的相关参数(位移, 加速度…)
  3. scrollViewDidEndDecelerating:等一些标志拖动结束的delegate方法中调用snapToPage方法, 在snapToPage方法中, 借助之前收集的动作参数计算出contentOffset, 并通过setContentOffset:offset animated:YES来移动.

这种方式的关键就在contentOffset的计算中(DMPagingScrollView.m pageOffsetForComponent:方法), 如果计算的不正确, 就会严重影响拖动UIScrollView的手感.

DMPagingScrollView通过subclassing UIScrollview将自定义分页相关的过程操作封装在DMPagingScrollView里面, 同时支持横向纵向的自定义分页, 十分方便. 类似地, 我们也可以对UITableView, UICollectionView进行同样的处理.

此外, 通过参考pageOffsetForComponent:中的计算方法, 我们甚至可以让每一页的宽度都不同, 从而大大提升了分页的灵活性, 比如我实现的这种:

- (CGFloat)pageOffset {
    CGFloat totalWidth = self.collectionView.contentSize.width;
    CGFloat visibleWidth = self.collectionView.bounds.size.width;

    CGFloat currentOffset = self.collectionView.contentOffset.x;
    CGFloat dragVelocity = _dragVelocity.x;
    CGFloat dragDisplacement = _dragDisplacement.x;

    NSInteger nearestIndex = 0;
    CGFloat minDis = CGFLOAT_MAX;
    CGFloat nearestOffset = 0;
    CGFloat prevOffset = 0;
    CGFloat nextOffset = 0;
    CGFloat totalOffset = 0;

    // self.pagesWidths is an NSArray that contains each page's width
    for (NSInteger i = 0; i < self.pagesWidths.count; i++) {
        CGFloat dis = ABS(totalOffset - currentOffset);

        if (dis < minDis) {
            minDis = dis;

            prevOffset = nearestOffset;
            
            nearestOffset = totalOffset;

            if (i == self.pagesWidths.count - 1) {
                nextOffset = totalOffset;
            }
            else {
                nextOffset = totalOffset + [(NSNumber *)self.pagesWidths[i] floatValue];
            }
        }

        totalOffset += [(NSNumber *)self.pagesWidths[i] floatValue];
    }

    NSInteger lowerIndex;
    NSInteger upperIndex;
    CGFloat lowerOffset;
    CGFloat upperOffset;
    if (currentOffset - nearestOffset < 0) {
        lowerIndex = nearestIndex - 1;
        upperIndex = nearestIndex;

        lowerOffset = prevOffset;
        upperOffset = nearestOffset;
    }
    else {
        lowerIndex = nearestIndex;
        upperIndex = nearestIndex + 1;

        lowerOffset = nearestOffset;
        upperOffset = nextOffset;
    }

    CGFloat newOffset;
    if (ABS(dragDisplacement) < DRAG_DISPLACEMENT_THRESHOLD || dragDisplacement * dragVelocity < 0) {
        if (currentOffset - lowerOffset > upperOffset - currentOffset) {
            newOffset = upperOffset;
        } else {
            newOffset = lowerOffset;
        }
    } else {
        if (dragVelocity > 0) {
            newOffset = upperOffset;
        } else {
            newOffset = lowerOffset;
        }
    }

    if (newOffset > totalWidth - visibleWidth)
        newOffset = totalWidth - visibleWidth;

    if (newOffset < 0)
        newOffset = 0;

    return newOffset;
}

–以上–

Tagged with:  

kernel_task占用大量CPU的解决方案

On 06/23/2013, in Apple, by ultragtx

如果你在使用MacBook、MacBook Pro、MacBook Air或者其他可能的Mac设备(我不知道iMAC和Mac mini有没有这个问题)遇到kernel_task长时间占用大量CPU(通常是500%-600%,也有200%,视机型而定)的情况,如果你正在播放Flash、进行高强度运算,或者正值高温天气。那么本文很可能会挽救你于水深火热之中。

首先解释一下kernel_task为什么会占用如此多的CPU。相信你从前文的描述中就可以发现,这是机器过热造成的。事实上kernel_task并不是真的在占用大量CPU,这么做的目的只是为了从那些疯狂消耗CPU的程序中抢夺系统资源,从而达到降低系统开销的目的,进而降低了机器的温度,一旦温度低到一个值,kernel_task也就恢复正常了。这在环境温度比较低的情况下是非常有效的降温手段,而在炎热的夏季,就会有kernel_task迟迟不能恢复正常的情况发生。

根据上面的分析,我们可以发现解决问题的关键就是如何让机器温度快速降低下来。方法自然有很多了,搞个大风扇对着电脑狂吹,在保证机器安全的情况下往机器上浇点水什么的,或者找个调解风扇转速软件(显然我不知道什么软件好用,因为我用了前两种方法)。还可以参考一下这篇文章的内容及相关讨论。

希望本文能帮助到被这个问题困扰着的人。如果本文没有解决你的问题,那么也有可能是其他原因造成kernel_task疯狂占用CPU,你可以尝试一个一个关闭正在运行的程序,看看是哪个造成的问题,不行就去Genius Bar求助吧。

–以上–

Tagged with:  

No Comments

On 06/13/2013, in 未分类, by ultragtx

Sorry_Steve

designed by  Artur Kasimov

 

最近做的一个项目中涉及这样一个需求: 响应用户点击html元素的事件.这其中包含响应单击(single tap/click)和双击(double tap/dblclick).

单击事件

通常单击的解决方案是用javascript实现, 为html元素绑定onclick事件, javascript接收事件后跳转url, 在CocoaTouch中用 webView:shouldStartLoadWithRequest:navigationType: 拦截url跳转, 从而实现单击事件的响应, 大致的代码如下:

Javascript:

function myClick() {
    var e = window.event
    var url = "click:" + e.target.id;
    document.location = url;
}

var ele = document.getElementById(ELEMENT_ID);
ele.onclick = myClick;

CocoaTouch:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

    NSString *requestString = [[request URL] absoluteString];
    NSArray *components = [requestString componentsSeparatedByString:@":"];
    if (components.count == 2 && [(NSString *)[components objectAtIndex:0] isEqualToString:@"click"]) {
        NSString *eleIdStr = (NSString *)[components objectAtIndex:1];
        NSInteger eleId = [eleIdStr integerValue];

        // Do something

        return NO;   // Do not load request, just receive the event
    }
    return YES;
}

双击事件

Failed 1

使用与上面同样的方法为html元素添加ondblclick来响应双击事件就无法实现, 现象为响应函数从不被调用. 用setTimeout等方法尝试用单击事件来模拟双击事件也无法实现, 无法接收到double tap的第二次点击.

Failed 2

根据之前的现象来看, 显然双击事件在html之外就被拦截了, 要从CocoaTouch层下手才行.

系统的UIWebView中包含了一个UIScrollView, 绑定了UIScrollViewDelayedTouchesBeganGestureRecognizerUIScrollViewPanGestureRecognizer这两个事件, 后者响应拖动事件, 前者相应点击事件.

尝试添给UIScrollView加UITapGestureRecognizer:

UITapGestureRecognizer *dblTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(fakeTapGestureHandler:)];

经测试, fakeTapGestureHandler:从未被调用过.

Success

尝试曲线救国的方式, 用UIGestureRecognizer的delegate方法获取事件:

Javascript:

function eleIdFromPoint(x, y) {
    var ele = document.elementFromPoint(x, y)
    return "" + ele.id;
}

CocoaTouch:

// Add gesture
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(fakeTapGestureHandler:)];

[tapGestureRecognizer setDelegate:self];
[_webView.scrollView addGestureRecognizer:tapGestureRecognizer];

// Delegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint tapPoint = [touch locationInView:_webView];
    NSString *script = [NSString stringWithFormat:@"eleIdFromPoint(%f, %f)", tapPoint.x, tapPoint.y];
    NSString *eleIdStr = [self stringByEvaluatingJavaScriptFromString:script];
    if (touch.tapCount == 2) {
        if (eleIdStr.length > 0) {
            NSInteger eleId = [eleIdStr integerValue];

            // Do somthing

        }
    }
    return YES; // Return NO to prevent html document from receiving the touch event.
}

上面代码通过UIGestureRecognizer的delegate方法成功获取到点击事件, 需要说明的几点:

  • locationInView:的参数为UIWebView, 后面的document.elementFromPoint传递的也是UIWebView中对应的坐标, 不需要算上UIScrollView的Offset.
  • delegate方法中单击事件也可以被拦截到, 这样单击双击就可以在这块儿一起实现, 让代码看起来比较统一.
  • delegate方法返回NO会拦截事件, html文档就不能接受到任何点击事件了.

–以上–

Tagged with:  

这篇属于技巧性文章, 没什么营养.

如果你常写NSTask相关的东西, 可能需要设置一个脚本的权限为可以执行. 有各种Unix方法, 也有只用Cocoa就能实现的:

1
2
3
NSNumber *permissions = [NSNumber numberWithUnsignedLong: 493];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:permissions forKey:NSFilePosixPermissions];
[NSFileManager defaultManager] setAttributes:attributes ofItemAtPath:path error:&amp;err]

简单解释一下那个"493", 这个就是十进制的"755", 也就是"rwx-xr-x", 所以如果你想要"777"的权限, 就用"511".

用NSFileManager创建文件的时候也可以传递上面的attributes, 创建可执行的文件.

–以上–

Tagged with:  

Fusion Drive组建及Bootcamp安装

On 04/09/2013, in 折腾, 硬件, by ultragtx

本教程将涉及

  • 硬件安装
  • 系统安装,Fusion Drive创建,及保留Recovery分区
  • Fusion Drive以后如何Bootcamp装Windows

安装硬件

硬件选购参考(购于Taobao)

FDnBI m5s

Plextor m5s 256G:这个不用说吧,1.0.3固件,东芝颗粒,速度快,便宜。

FDnBI optbay

光驱位硬盘托架 佳翼H125 :做工一般般,不过这个价格也找不出做工好的,需要高质量的去买OWC Data Doubler

FDnBI usbsata

光驱盒替代品:这个小玩意跟上面那个光驱托架一起买只要9.9,特便宜,相对来讲那个光驱盒目测质量不敢恭维,买个这个凑合一下,反正光驱也不常用。另外有一点要注意,拆下来的光驱在读盘的时候会从各种缝隙漏出激光,直射眼睛可能会造成伤害,尤其是刻录的时候,要知道DVD刻录光驱的激光是可以点烟的,所以如果常用光驱还是建议买一下光驱盒

关于SSD,HDD分别放在哪些位置

注意事项:

(其中没有实际测试过的,不能保证100%的正确性)

速度方面:
  • 2011年以后的机器硬盘位支持SATA III 6Gb/s
  • 2012年以后的机器光驱位支持SATA III 6Gb/s
  • 2011年春季的机器光驱位有部分“看起来”支持SATA III 6Gb/s 部分支持SATA II 3Gb/s
  • 2011年秋季的机器光驱位全部“看起来”支持SATA III 6Gb/s
  • 可以在"系统报告/串行ATA/链接速度" 查看是否“看起来”支持SATA III 6Gb/s
  • 2011年光驱位看起来支持SATA III 6Gb/s的机器,将支持SATA III的SSD放入光驱位会有问题,传说Intel的SSD没有问题,具体见这里最后一楼这里的讨论。再次强调,Intel的SSD没有经过测试,其他厂商SSD放在光驱位几乎可以肯定会出问题。
  • SATA III的设备安装在
  • 一些机械硬盘是SATA III 6Gb/s的,这种情况下将机械硬盘放到有问题的光驱位也可能有问题。
  • SATA III的设备理论上是兼容SATA II的,所以只要不是2011年有问题的机器,
安全方面:
  • HDD位有移动感应,据说可以在检测出电脑移动的时候让硬盘磁头跟盘面分离。
  • 视不同的硬盘,有些硬盘内建重力感应,也就是说自带一定减震效果

根据以上条件:

  • 如果你的设备为2011年,光驱位“看起来”支持SATA III的机器,又购买了非Intel的SSD,那么SSD只能放到HDD位,光驱位放原来的硬盘。
  • 如果没有上述问题,尽量将SSD放到光驱位,硬盘放在硬盘位,既保证硬盘的安全,同时硬盘噪音会小很多。

实测“伪”SATA III装SATA III SSD后的问题:

  • 向SSD写数据,会间歇性暂停传输,传输速度为0,如果系统安装在上面就会出现系统间歇性卡顿,难以使用
  • 写入数据速度最高仅200MB/s,正常应达到360MB以上
  • 有时会直接无法写入

拆机

根据上一部分的判断,选择性拆光驱、硬盘。建议先看一下王自如拆机组RAID的视频,做到心里有数,拆的时候不要心急。

以2011 late Macbook Pro(MD318/MD322)为例:

拆光驱(如图所示):

FDnBI breakout

  1. 背盖
  2. 拆绿色部分,顺序无所谓
  3. 紫色部分,撕开与光驱相连的黑色胶布
  4. 蓝色部分,顺序无所谓

一些说明:

  • 红色部分的线跟视频中位置不同,如图所示情况下不需要拆,实际只要不会影响取出光驱就没必要拆这根线,而且这根也较难拆
  • 蓝色部分除7之外,所有的都是6角螺丝,需要特殊的螺丝刀
  • 绿色部分除1之外,所有的都是十字螺丝
  • 蓝4,在红色部分线下面,需要将红线移开一些才能接触到
  • 蓝5,需要拿开上面的黑色塑料模块才能看到

拆硬盘

  • 跟视频中的方法一样,注意排线。

安装OSX

本文创作时,OSX最新版本为10.8.3,一切内容均以此版本为基准。

安装OSX 10.8.3 Mountain Lion

安装流程:

WARNING

以下操作会清空所有数据,切记在执行前备份重要数据!

  1. 制作安装光盘/U盘

  2. 重启,安装盘引导,查看磁盘列表

     diskutil list 
  3. 创建逻辑卷组(Logical volume group)。其中,cs为coreStorage简写;FusionDrive为卷组名字,随便起;disk0为SSD,disk1为HDD,根据上一步的结果自行修改为合适的值

     diskutil cs create FusionDrive disk0 disk1 
  4. 查看创建结果,复制逻辑卷组的UUID(eg. "+– Logical Volume Group 2B4EDB74-5842-40E4-8398-1567CD879127",这一行最后一串数字字母)

     diskutil cs list 
  5. 创建卷。后面2B4…127为之前复制的UUID,FusionDrive为名字,100%为容量

     diskutil coreStorage createVolume 2B4EDB74-5842-40E4-8398-1567CD879127 jhfs+ FusionDrive 100% 
  6. 在Fusion Drive上安装系统

  7. 装好系统想着开启Trim:方法(适用于10.8.3,其他未测试)

参考链接:

关于Recovery HD问题

虽说按上面教程安装后用开机按option看不到Recovery分区,但开机按Command + R还是可以进入Recovery的。

这个链接 DIY Fusion Drive: Adding Recovery HD to a CoreStorage Volume Group里有创建Recovery分区的方法,实测@robmathers的方案在开机Option中还是看不到Recovery,也可能是我操作有问题。

Bootcamp

几点说明:

  • Macbook Pro通过Bootcamp安装Windows需要内置光驱,外置以及USB引导安装盘都无解
  • Fusion Drive后,Bootcamp分区是从HDD上分割出来的,不会用到SSD
  • 在Bootcamp 5下,光驱位HDD上的Windows是可以引导的(有传言不能引导)

准备工作:

  • Virtualbox,虚拟机,用于制作Windows磁盘镜像。
  • Windows 7 64bit,或Win 8 64bit 安装镜像。32位Bootcamp说不支持,未测试。
  • Winclone,用于将磁盘镜像写入Bootcamp分区

安装

创建虚拟磁盘

  1. VirtualBox新建虚拟机,命名为“Windows”,磁盘文件类型VDI,动态分配,大小10G(不要给大,影响后面转换的速度)。
  2. 虚拟机设置里面设置好Windows安装光盘镜像
  3. 启动进入安装界面,Shift+F12打开CMD,输入下面命令,手动创建分区,避免Windows自动创建100MB分区

     diskpart select disk 0 create partition primary exit exit 
  4. 开始安装,选择刚才创建的分区,继续

  5. 第一次重启的时候关闭虚拟机,注意是关闭不是暂停
  6. VirtualBox菜单/管理/虚拟介质管理,选择“Windows.vdi”,复制,文件格式选择vdi,固定大小,命名为“Windows_copy”
  7. 上一步复制完成后,打开终端,进入复制后文件所在目录,输入下面内容,转换虚拟磁盘:

     sudo VBoxManage internalcommands converttoraw Windows_copy.vdi Windows.raw 
  8. 转换结束后,终端接着输入下面内容,挂载虚拟磁盘:

     sudo hdiutil attach -imagekey diskimage-class=CRawDiskImage Windows.raw 

创建Bootcamp分区

  • 使用Bootcamp助理创建Bootcamp分区(需要Windows安装光盘,据说加载个镜像就可以,未测试,我用的是Bootcamp助理制作的USB安装盘)
  • 关于如何通过Bootcamp助理制作USB Windos安装盘(适用于Bootcamp 5):

    • Finder 找到 /应用程序/实用工具/Boot Camp 助理,显示包内容
    • 复制Contens/Info.plist到桌面,修改“PreUSBBootSupportedModels”下面的“MacBookPro8,3”为“MacBookPro7,3”,移动回原来的位置,替换。
    • 重启Bootcamp助理,可以看到制作USB Windos安装盘的选项
  • 创建Bootcamp分区后记得重启,你可以尝试不重启,但是可能会有个小问题,导致下面的步骤报错,重启能简单解决。

将虚拟磁盘镜像写入Bootcamp分区

  • 打开Winclone,应该可以看到一个Untitled,一个Bootcamp
  • 选择Untitled,写映像…,一切操作选择默认选项
  • 上一步完成后,选择创建好的winclone文件,选择Bootcamp分区为目的磁盘,恢复…,一切操作选择默认选项
  • 系统偏好设置,选择启动磁盘为windows
  • 重启进入Windows,继续安装,完成

参考链接:

Tagged with:  

Leap Motion Controller Hands-on

On 01/25/2013, in 评测, by ultragtx

Product hero 3610e3d732bde725cd2254ff8f67851e

昨日入手了开发版Leap Motion Controller,既然不要钱就不能白拿,先写个简单的试用体验,之后会研究研究开发一些应用出来(如果你还不知道这个东西是干什么的,请点前面的链接到官网看看)。关于Leap Motion Controller比较面向消费者的介绍可以看下ifanr的文章,本文主要以Geek和开发角度评价。

我手上的Leap Motion版本应该可能是Rev6(虽然盒子上写的Rev5),先贴两张我自己照的图,这里先说明一下,图中Leap Motion上3浅紫色的光源用肉眼看只是3个很暗的红色光源,只有通过相机镜头才会看到图中这样的效果,原因应该就是相机的感光范围比肉眼广吧。

LeapMotion 001

LeapMotion 002

基本工作原理

借助相机的这个特殊效果,我们也能大概推测一下Leap Motion的工作原理,仔细看上面第二张图,能发现一些均匀排列的光点(如下图所示),在最下面的官方“解剖”图中还可以看到主板上的两个镜头,知道了这些,Leap Motion Controller大概的工作原理我也不用再多说什么了。

LeapMotion 002 1

Overview2

工作模式及识别效果

Leap Motion有3种主工作模式,Balanced、Precision、High-Speed,此外在这三种基础之上还有Low-Resource模式,Robust模式两种辅助模式,Balanced,Precision、High-Speed这三者之间的区别在于如何权衡识别精度和识别速度,精度越高,速度(帧数)就越慢,具体参见下表:

Modes USB 2.0 USB 3.0
Precision 60  fps 80  fps
Balanced 120 fps 150 fps
High-Speed 214 fps 295 fps

 

至于Low-Resource模式,主要用来降低CPU使用率,当然相应帧数也会有所降低。Robust模式则是针对poor lighting环境做出一些优化同时也会牺牲一些识别的范围和精度(这里的poor lighting我推测是在强光环境下)。

LeapMotion 003

用自带的Visualizer(如上图)实际体验,三种主模式主要的区别就在帧数上有不同,具体要针对不同的应用做选择,只通过这个Visualizer看不出来太多东西。Low-Resource模式关闭的情况下,CPU占用持续维持在50%左右(MBP 15 Late 2011),开启Low-Resource后降低到20%,如果把Leap Moution Controller当做一个像鼠标、触摸板这种日常使用的输入设备的话,不开启Low-Resouce模式,这种持续的高百分比CPU占用基本是不能忍受的,开启Low-Resource也就勉勉强强可以接受,不知道官方准不准备优化这一“问题”。Robust没测试,反正官方也说这个模式在今后开启的机会会越来越少。至于识别方面,Leap可以识别手指,手,以及类似笔这种细长形状的工具,识别精度很好,手指的轻微移动都可以准确反映出来,不足之处是只有手水平放置才能正确识别,垂直就不行,从官方的演示视频也可以看出,演示者一直都在避免让手指纵向排列,不知道这一问题会不会对最终的用户体验造成太多影响,另外要准确识别所有手指需要把手指伸直,时间长了可能会比较累。

开发

目前的SDK(0.7.1)虽然各种语言、平台覆盖的还算全面,但是功能比较弱,只能得到每一帧识别出的手指手掌等的坐标和所指方向等信息,还没有一套封装好的手势,这就导致了开发者如果对手势识别技术不熟悉,就没法开发出体验很好的应用,不同的开发者开发出来的应用的“手感”也会有差距,用户就很难适应,更何况一个优秀的手势识别系统不是轻易就能开发出来的,幸好官方已经将手势识别提上日程,对于大部分开发者来说也就只能“坐等”更新了。

第三方应用暂时都在Demo级别,数量也很少,但是开发者的热情普遍很高,相信随着更多的开发者收到设备,目前的状态会很快得到改变。

总结

从目前来看,Leap Motion Controller还只能算是一个新颖的产品,距离“创造新时代”还是有些遥远。虽然有很多令人称赞之处,但如果没有一套优秀的手势识别系统支撑,加上纵向识别的不足,用户输入的错误率就会比较高,不能带来像苹果的触摸板那样优秀的体验,能否真正成为一款跨时代的产品还需要硬件商和开发者的共同努力。

–以上–

Tagged with:  

开篇扯淡是惯例(其实这个博客是一个AI维护的你信么?), 又是一个多月没写东西,折腾各种东西,写不出来什么有营养的,也就放着了。本文虽然谋划已久,但一直都没动手写,在iOS这块,虽然坚持2年了,但还是担心会误导别人,不敢写这种类型的东西。最近要集中点别的技能点,iOS会放缓,先把这篇放出来吧,供大家参考,为了方便搜索,给本文起个中文标题:学习iOS,从菜鸟到小强。

啰嗦版

先说下我开始折腾iOS这块之前的知识背景,“碰过“C/C++,“看过”Java,“碰过”Android,当然这些都是比较保守的说法,不过也基本可以认为就是大菜的水平,认为什么都不会也可以,但是有过几个较完整的项目经验(比如我写过俩android小破项目)。

开始的时候,我的路线是在基本什么都不会的情况下,以一个不大不小的项目驱动,快速产出,这里最重要的一点就是学会如何在什么也不懂的情况下搜索到你想要实现的那些东西的代码,或者是相似的代码,然后就是如何照猫画虎把别人写的几块东西改改,用胶水代码沾一起,形成一些“能用的”东西,快速的产出有助增强信心,有效避免半途而废,同时一旦开始写代码了,所学到的知识就自然而然记牢了,不会发生看一遍忘一遍这种情况。

当然如果我这么建议别人,一些大神就会喷了(比如这个:【豆瓣校招-面试官发声】近期面试感受),说这种搜索式学习方式会打下不好的基础,因为你接触到的都是二手,三手以上的信息(这里定义一下,一手信息为文档,质量最高,二手信息可以认为是StackOverflow这类,也很不错了,三手就是这个链接里所表达的那个“二手”),对这些信息就要比较谨慎,有些东西可能太过技巧,不是一种好的解决方法,另外就是难免有错误,而且这个错误可能会被你继承很久,因为是新手,你会倾向于相信所有“好使“的代码。

这些弊端确实存在,不过恭喜你学习的是iOS,只要将你寻找问题解决方法的搜索范围限定在官方文档,WWDC视频,StackOverFlow上就可以了,这些都是一手二手的信息,而且一手信息占了绝大多数,基本可以保证信息的优质性,同时也完全足够解决问题了。当然多看看其他人写的东西也是有好处的,学习不要死板,这里的限制只是在避免上一段提到的问题,搜索式学习虽有弊端,但还是要比啃一手资料快很多,对于优先实现功能是很有必要的,关键就是要和一手资料结合着用,如何掌握之间的度就靠自己来衡量吧。

这里不得不提一下文档,苹果的文档是我见过的最好的文档(MSDN的也很牛,但是我没做过windows那方面的开发,所以没什么了解),这里不仅仅有对类、方法的详细说明,还有非常多的XXX Programming Guide,这种导引性的文章,从一定程度上来说,有了文档我们甚至已经不再需要StackOverflow,其实在StackOverflow搜索问题的时候,很多回答就是一个指向官方文档的链接。同时,文档中包含了大量Sample Project,这些Sample都很有针对性,清晰地展示了各种实现方法,同时Sample的代码都是高手写的,多看看Sample Project对编程能力的提升也有很高价值。额外说一句,如果你认为英文的文档太难读懂,那就只能查着字典啃,如果还是不行,你去学英文吧,要么就别搞这一行,文档的英文要求已经很低了。

WWDC视频,也是快速解决问题的必备,在接触比较陌生的一块比如音频处理的时候,先看一看WWDC相关视频,就能大概了解一下相应的实现方法,对这一块有一个比较清晰全面的认识,这时候再借助文档的XXX Programming Guide,基本就可以非常深入地学习到你需要的知识。

前面一直都没提到,书–这一重要学习工具,在我看来买书基本上完全没有必要,有文档在看什么书啊,那种讲语言,讲SDK的书没有必要买,根本比不上文档,时效性也差。当然还是有些好书值得买来看看,比如Apress的iPhone Cool Projects,和More iPhone Cool Projects,虽然比较旧,但是里面那几个项目还是很有参考价值的。

面对iOS这一快速更新的系统,新手面临的一个常见问题就是该从哪个SDK版本入手。SDK版本对于新手老手都是个问题,要想要新功能,就要高版本的SDK,要想兼容旧设备,就要放弃新功能,或者自己实现新功能,选择低版本的SDK。这里根据我的经验,如果你是一个纯新手,不着急开发产品,就从最新的SDK版本入手,因为等你出师了,当时入门的SDK版本已经是旧版了,兼容旧设备的问题就不存在了。如果要快速出产品,那就只能从低版本SDK入手了,当然有些新API就用不了了,作为新手一个能用新API很方便实现的功能却要为了兼容用很复杂的方法实现还是有些不爽的。选择SDK要注意的一点就是,在iOS 4.0以后,引入了Auto Reference Counting(ARC)这一技术,个人感觉使用ARC虽然方便了内存管理,但是对于新手来说缺少了手动管理内存的历练,这里欠下的债,将来一定要还的。所以还是推荐先看文档学习一下内存管理方法,并在此后一段时间内关掉ARC实践手动管理内存,记得用Instruments测一下内存泄露,等到基本掌握了手动内存管理,就可以开ARC了。当然,我在折腾内存管理的时候还没有ARC,所以这部分建议可能存在一点主观因素,虽然不一定是最好的路线,但总不是错误的路线。

工欲善其事,必先利其器,XCode的熟练使用,对于提高效率至关重要,关于怎么使用XCode请搜索我以前的文章,关键词“XCode”,懒,不发链接了。

以上都是以项目驱动为前提,至于这个项目,规模不要太大也不要太小,有一定升级空间,最好是没有时间限制的长期项目,这样就有充足的时间来深入研究某一部分知识点,第一个版本功能实现了,但是代码不够漂亮,效率不够高,推到重来是一个非常好的选择,反复迭代几次,大有益处。

我的入门项目就是HIT Mobile(在关于页面里面有链接,现在也基本停止维护了,实际上也没什么人用)。这个项目我和一个队友分别负责不同的功能,持续时间将近一年(当然有上课考试等因素干扰),为了代码整洁或者效率等问题,每个功能都反复写了2、3遍,这几遍推到重来对能力的提升是非常大的。

虽然做单一的项目可能接触的不够全面,但如果你是一个渴求知识的人,必然会在做主线任务的同时,走一些分支路线,接触到其他方面的知识,另外一点就是,iOS虽然是个手机上的OS,但不要忘了这是基于Mac OS做出来的系统,Mac OS这么多年历史岂是我等弱菜一两年就能接触全面的,专注一两个点深入学习下去也是一种很好的选择。

我们还没有说github,github的重要性其实根本不必多提,开源的framework,控件什么的基本都在上面。其他网站比如,CocoaControls,有很多开源的UI控件,建议订阅个RSS。此外cocoaneticsCocoa is my girlfriend等博客类型的网站也经常会发布一些非常优秀的文章。

总之想“精通”iOS,绝对不是短时间可以做到的,贵在坚持不断学习。

精简版:

  • 项目驱动
  • 寻找帮助
    • 文档
    • WWDC视频
    • StackOverflow
    • Google
  • 书,不是很必要
  • 学习XCode使用
  • 手动管理内存,熟练以后再开启ARC
  • 找代码,开源库:github, CocoaControls
  • 好文章:
    • cocoanetics
    • Cocoa is my girlfriend
    • 等等

补充:

一些非常好的资源:

  • RAYWENDERLICH   |  简单高质量的Tutorial,涵盖iOS Mac Cocos2D Unity等内容

 

–以上–

Tagged with: