新年之际,盘点一些APP开发技巧

(原文:Reader Submissions - New Year‘s 2015 作者:Mattt Thompson 译者:培子 校对:蓝魂)

回顾过去一年发生在我们身边的事情时,有一点不得不提:对苹果开发者来讲,2014年是令人难以置信的一年。在这短短的一年中(有关APP的开发)发生了如此多的变化:在充满吸引力的Swift面前,我们几乎忘了之前是如何痴迷于Objective-C;以及充满想象力的iOS 8和WatchKit,难以想象还有什么API能与之相比。

NSHipster的惯例:请可爱的童鞋们,在新年的第一天,为大家展示你们(在开发中)常使用的技巧和方法。如今,随着来自库比蒂诺(Cupertino,苹果总部,位于旧金山)和众多开源社区的一系列API的涌现,妈妈再也不用担心我们找不到有趣的东西来分享啦!

在此,感谢以下童鞋们所做的贡献:

Colin Rofls, Cédric Luthi, Florent Pillet, Heath Borders, Joe Zobkiw, Jon Friskics, Justin Miller, Marcin Matczuk, Mikael Konradsson, Nolan O‘Brien, Robert Widmann, Sachin Palewar,Samuel Defago, Sebastian Wittenkamp, Vadim Shpakovski, and Zak

成员函数的使用技巧
(来自 Robert Widmann

在用静态方式调用Swift类和结构中的成员函数时,通常使用以下格式:

Object->(参数)->Things

比如,你可以用以下两种方式调用reverse():


1

2

[1,2,3,4].reverse( )

Array.reverse([1,2,3,4])

用@()来封装C字符串
(来自 Samuel Defago

事实上文字大部分时候是数字和字母的集合,使用C字符串,尤其当我在使用运行时编码的时候,我常常会忘记用UTF8编码、以NULL结束:Objective-C字符串封装:


1

2

3

NSString *propertyAttributesString =

    @(property_getAttributes(class_getProperty([NSObject class], "description")));

// [email protected]"NSString",R,C

AmIBeingDebugged

Nolan O‘Brien这篇Q&A技术文档中让我们注意到了AmIBeingDebugged函数方法:

使用延迟存储属性
(来自 Colin Rofls

在开发过程中,应该避免使用Optionals类型,更不应该使用隐式解包optionals类型。你想声明一个var变量却不想给一个初始值?使用“lazy”吧,唯一要注意的就是:在你的属性被赋值之前不要调用getter方法即可(童叟无欺!)


1

lazy var someModelStructure = ExpensiveClass()

假如你仅仅对这var变量调用set方法,而没有调用getter方法的话,这个被lazy修饰的var变量不会被赋值。例如,用lazy修饰那些直到viewDidLoad时才需要初始化的views变量就会非常合适。

获取Storyboard视图容器里的子视图控制器
(来自 Vadim Shpakovski

有一个比较方便的方法来获取故事板视图容器里的子视图控制器:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

// 1. A property has the same name as a segue identifier in XIB

@property (nonatomic) ChildViewController1 *childController1;

@property (nonatomic) ChildViewController2 *childController2;

// #pragma mark - UIViewController

- (void)prepareForSegue:(UIStoryboardSegue *)segue

                 sender:(id)sender

{

    [super prepareForSegue:segue sender:sender];

    // 2. All known destination controllers assigned to properties

    if ([self respondsToSelector:NSSelectorFromString(segue.identifier)]) {

        [self setValue:segue.destinationViewController forKey:segue.identifier];

    }

}

- (void)viewDidLoad {

    [super viewDidLoad];

    // 3. Controllers already available bc viewDidLoad is called after prepareForSegue

    self.childController1.view.backgroundColor = [UIColor redColor];

    self.childController2.view.backgroundColor = [UIColor blueColor];

}

重复运行项目,不重复构建项目
(来自 Heath Borders

假如你一直在不停地调试同一个问题,你可以在不重复构建的情况下运行你的APP,这样:“Product>Perform Action>Run without Building” (快捷键??R: Command + R)

快速获取Playground资源
(来自 Jon Friskics

Swift里的所有Playground共享相同的数据目录:/Users/HOME/Documents/Shared Playground Data

如果你喜欢使用很多Playgrounds,你将需要在上述共享目录下为每个Playground新建对应的子目录,来存储每个Playground用到的数据;但是那之后你需要告诉每个Playground在哪儿可以获取其对应的数据。下面是我常用的一个辅助解决方法:


1

2

3

func pathToFileInSharedSubfolder(file: String) -> String {

    return XCPSharedDataDirectoryPath + "/" + NSProcessInfo.processInfo().processName + "/" + file

}

processName属性是Playground文件的名字,因此只要你已经在Playground数据共享文件目录下以相同的名字新建了一个子目录,那么你可以很容易访问这些数据,和读取本地JSON数据一样:


1

2

3

var jsonReadError:NSError?

let jsonData = NSFileManager.defaultManager().contentsAtPath(pathToFileInSharedSubfolder("data.json"))!

let jsonArray = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &jsonReadError) as [AnyObject]

....或者 访问本地图片


1

2

let imageView = UIImageView()

imageView.image = UIImage(contentsOfFile: pathToFileInSharedSubfolder("image.png"))

-----------------------------------------------------------------------

Please attention!本篇文章剩余的部分来自Cédric Luthi大神的贡献,他分享了一些比较有用的开发技巧和技术,这些内容足够自成一篇,值得细细品读。这里再次感谢Cédric!

CocoaPods大揭秘

这儿有一个快速的方法来检查APP里用到的所有pods:


1

$ class-dump -C Pods_ /Applications/Squire.app | grep -o "Pods_\w+"

CREATE_INFOPLIST_SECTION_IN_BINARY

注意Xcode中为命令模式APP(command-line apps)设置的CREATE_INFOLIST_SECTION_IN_BINARY属性。这比使用-sectcreate__TEXT__info_plist链接标志位更加容易,前者还把已经编译好的Info.plist文件嵌入在二进制编码中。

关于如何向苹果提需求,它也给我们上了一课,这个特性需求早在2006年的 rdar://4722772 被提出,但直到7年后才被满足。

(译者注:言外之意是它是反面教材,应该更有技巧的提需求)

禁用 dylib钩子
(来自 Sam Marshall

Sam Marshall这个技巧可谓是走自己的路,让黑客无路可走。

在你的“Other Linker Flags”里加上下面这行:


1

-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null

NSBundle -preferredLocalizations

某些时候,你需要知道APP当前使用的是什么语言。通常,大家会使用NSLocal+preferredLanguages. 可惜的是这个方法不会告诉你APP实际呈现的文字语种。你仅仅会得到iOS系统里“Settings->General->Language&Region->Preferred Language”列表中的选项,或者OSX系统里“System Preferences->Language & Region->Preferred Languages”列表中的选项。想象一下:优先语言列表中只有{英语,法语},但你的APP仅使用德语;调用[[NSLocal preferredLanguages] firstObject]返回给你的是英语,而不是德语。

正确的方法是用[[NSBundle mainBundle] preferredLocalizations]方法。

苹果的开发文档是这样说的:

一个包含了在bundle中本地化的语言ID的NSString对象的数组,里面的字符串排序是根据用户的语言偏好设置和可使用的地理位置而来的。

NSBundle.h里的备注:

一个bundle中本地化的子集,重新排序到当前执行坏境的优先序列里,main bundle的语言顺序中最前面的是用户希望在UI界面上看到的语种。

当然你也许需要调用这个方法:


1

NSLocal+canonicalLanguageIdentifierFromString:

来确保你使用的文字语种是规范的语种。

保护SDK头文件

如果你用dmg安装Xcode,那么看看这篇Joar Wingfors的文章,它讲述了如何通过保留所有权来避免SDK头文件被意外修改:


1

$ sudo ditto /Volumes/Xcode/Xcode.app /Applications/Xcode.app

任意类型的实例变量检测

为了达到逆向处理的目的,查询对象的实例变量是一个常见可靠的途径。通常调用对象valueForKey:方法就能达到这一目的,除了少数重写了类方法+accessInstanceVariablesDirectly的类屏蔽了该操作。

下面是一个例子:当实例变量有一个为任意类型的属性时,上述提到的操作无效

这是iOS6.1 SDK中MediaPlayer 框架的一段引用:


1

2

3

4

@interface MPMoviePlayerController : NSObject {

    void *_internal;    // 4 = 0x4

    BOOL _readyForDisplay;  // 8 = 0x8

}

因为 id internal=[moviePlayerController valueForKey:@”internal”] 无效,下面有一个笨办法来取得这个变量:


1

id internal = *((const id*)(void*)((uintptr_t)moviePlayerController + sizeof(Class)));

注意!不要随意调用这段代码,因为ivar的布局可能改变(指针偏移量计算可能出错)。仅在逆向工程中使用!

NSDateFormatter +dateFormatFromTemplate:options:locale:

友情提示:假如你调用[NSDateFormatter setDateFormat],而没有调用[NSDateFormatter dateFormatFromTemplate:options:local:],n那么很可能出错。

苹果文档


1

2

3

+ (NSString *)dateFormatFromTemplate:(NSString *)template

                             options:(NSUInteger)opts

                              locale:(NSLocale *)locale

不同地区有不同的日期格式。使用这个方法的目的:得到指定地区指定日期字段的一个合适的格式(通常你可以通过currentLocal查看当前所属地区)

下面这个例子给我们表现了英式英语和美式英语不同的日期格式:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];

NSString *dateFormat;

NSString *dateComponents = @"yMMMMd";

dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:usLocale];

NSLog(@"Date format for %@: %@",

    [usLocale displayNameForKey:NSLocaleIdentifier value:[usLocale localeIdentifier]], dateFormat);

dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:gbLocale];

NSLog(@"Date format for %@: %@",

    [gbLocale displayNameForKey:NSLocaleIdentifier value:[gbLocale localeIdentifier]], dateFormat);

// Output:

// Date format for English (United States): MMMM d, y

// Date format for English (United Kingdom): d MMMM y

通过调试获取内部常量

近期, Matthias Tretter在Twitter上问到:

有人知道在iOS8里modal viewController presentation的默认动画时间和跳转方式吗?

我们在UIKit的类库中发现了这样一个函数:[UITransitionView defaultDurationForTransition:],并在这个方法的位置加一个断点:


1

(lldb) br set -n "+[UITransitionView defaultDurationForTransition:]"

模态显示一个viewController,就会停在这个断点,输入finish执行该方法:


1

(lldb)finish

在defaultDurationForTransition:被执行时,你就能读到结果(在xmm0寄存器里)


1

2

(lldb) register read xmm0 --format float64

    xmm0 = {0.4 0}

回复:默认动画时间0.4s

DIY 弱关联对象

不幸的是,关联对象OBJC_ASSOCIATION_ASSIGN策略不支持引用计数为0的弱引用。幸运的是,你可以很容易实现它,你仅仅需要一个简单的类,并在这个类里弱引用一个对象:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

@interface WeakObjectContainter : NSObject

@property (nonatomic, readonly, weak) id object;

@end

@implementation WeakObjectContainter

- (instancetype)initWithObject:(id)object {

    self = [super init];

    if (!self) {

        return nil;

    }

    self.object = object;

    return self;

}

@end

然后,通过OBJC_ASSOCIATION_RETAIN(_NONATOMIC)关联WeakObjectContainter:


1

objc_setAssociatedObject(self, &MyKey, [[WeakObjectContainter alloc] initWithObject:object], OBJC_ASSOCIATION_RETAIN_NONATOMIC);

用object属性指向这个所需的引用计数为0的弱引用对象。


1

id object = [objc_getAssociatedObject(self, &MyKey) object];

在这么多日新月异的新技术推动下,我们将迎来一个充满无限可能和机会的一年。在此,祝大家2015年新年快乐!

愿编程路上,与君共勉。
(本文为CocoaChina组织翻译,本译文权利归译者所有,未经允许禁止转载。)

时间: 2024-08-05 00:13:18

新年之际,盘点一些APP开发技巧的相关文章

web app开发技巧总结

Web APP开发技巧总结 一.META/LINK相关: 1.百度禁止转码 通过百度手机打开网页时,百度可能会对你的网页进行转码,往你页面贴上它的广告,非常之恶心.不过我们可以通过这个meta标签来禁止它: <meta http-equiv="Cache-Control" content="no-siteapp" /> 相关链接:SiteApp 转码声明 2.添加到主屏后的标题(IOS) <meta name="apple-mobile-

这些APP开发技巧可少花60万!

用户需求——我偏不用干嘛要装? 随着手机的普及,大众流量的端口从电脑转移到手机,传统的商业平台从线下到电脑再到手机进行了转换.手机APP作为移动互联网的入口,众多创业者凭借一个手机APP成就了亿万财富.O2O模式不断深入到生活的细节,各类上门服务层出不穷. 但是,对互联网APP开发来说,要想实现产品的发展,必须要考虑这样一个问题:客户是否有需求?目前层出不穷的APP里,能够实现发展的只有实体辅助的电商.同城服务.企业品牌展示.自媒体. APP开发成本——我非要做得花多钱? 很多创业者认为,我的产

web app开发技巧总结 (share)

(转自http://hi.baidu.com/kuntakinte/item/ca92d6e5edae9fc0bbf37d08) 自Iphone和Android这两个牛逼的手机操作系统发布以来,在互联网界从此就多了一个新的名词-WebApp(意为基于WEB形式的应用程序,运行在高端的移动终端设备). 开发者们都知道在高端智能手机系统中有两种应用程序:一种是基于本地(操作系统)运行的APP:一种是基于高端机的浏览器运行的WebApp,本文将主要讲解后者. WebApp与Native App有何区别

Web APP开发技巧总结(转)

一.META/LINK相关: 1.百度禁止转码 通过百度手机打开网页时,百度可能会对你的网页进行转码,往你页面贴上它的广告,非常之恶心.不过我们可以通过这个meta标签来禁止它: <meta http-equiv="Cache-Control" content="no-siteapp" /> 相关链接:SiteApp 转码声明 2.添加到主屏后的标题(IOS) <meta name="apple-mobile-web-app-title&

前端读者 | Web App开发入门

本文来自互联网 自Iphone和Android这两个牛逼的手机操作系统发布以来,在互联网界从此就多了一个新的名词 - Web App(意为基于WEB形式的应用程序).业界关于Web App与Native App的争论已有一段时间,而Hybrid混合App则受到推荐,随着时间的推移,我们相信Web App也会有一定的市场,那么它到底有什么奥秘呢?让我们来看看. Web App与Native App有何区别呢? NativeApp 开发成本非常大.一般使用的开发语言为JAVA.C++.Objecti

App开发外包流程和防骗技巧

随着移动互联网的快速发展,app软件是每家互联网公司必备的.但是不少中小企业因为自身原因选择了把app外包出去,但是又担心app外包不可控,担心开发延迟甚至失败.今天51开发app官网(外包潜规则揭秘网),给大家分享一下app外包开发的大致流程.对外包流程有一个整体的了解,不仅能够消除你的担心,而且能够让你游刃有余的处理外包过程中所发生的一些意外,让app外包更加可控. 第一步:阐述需求,在产品经理或者项目经理的帮助下将需求细化并且做好需求文档 第二步:报价,按照app开发的功能需求进行报价,可

AppCan移动开发技巧:3步走,获取移动APP签名信息

大家知道,在移动APP开发里,与应用包名一样,应用的签名信息需是唯一的,否则将会出现应用冒领.重复安装等问题.之前分享过安卓应用的签名如何获取(点击查看),这里将继续以AppCan平台为例,分享如何获取APK包的签名信息及相关注意事项. 获取APK包签名信息 为了保证每个应用程序开发商的合法ID安全,防止部分开发商通过使用相同的包名混淆和替换已经安装的程序,开发者需要对发布的APK文件进行唯一签名,保证每次发布的应用版本的一致性(如果自动更新,则不会因为版本不一致而无法安装). 操作步骤: 1.

盘点国内外在线app开发平台:分分钟做款app

随着智能手机的飞速发展,现在各类型的App数不胜数,几乎覆盖了工作.生活.学习的方方面面.在你使用别人开发的app时,有没有想过我自己能不能做一款牛叉牛叉的app?我估计很多朋友们有很好的idea,但是因为技术问题,美工问题总是望而却步. 于是今天王哥给你挖掘出以下4款国内外知名度较高的在线App应用开发平台,据说他们能让毫无编码技术知识,美工基础的小白能在极短的时间内做一款属于自己的app应用.究竟是否如传言所说?接下来,就让我们一起来一睹为快吧,当然,自己亲身体验一番更是再好不过的了. 1.

iOS开发——使用技术OC篇&amp;项目实战总结之开发技巧

项目实战总结之开发技巧 本文收集了25个关于可以提升程序性能的提示和技巧 1.使用ARC进行内存管理 2.在适当的情况下使用reuseIdentifier 3.尽可能将View设置为不透明(Opaque) 4.避免臃肿的XIBs 5.不要阻塞主线程 6.让图片的大小跟UIImageView一样 7.选择正确的集合 8.使用GZIP压缩 9.重用和延迟加载View 10.缓存.缓存.缓存 11.考虑绘制 12.处理内存警告 13.重用花销很大的对象 14.使用Sprite Sheets 15.避免