Welcome to Office Reader

Tips:
1:To transfer files to Office Reader, use iTunes file sharing:
Open iTunes and connet your iPhone to iTunes use USB cable, then following the 4 steps:
FileSharingEn.png
2:Use double tap to switch between full screen and non-full screen.
3:You can print files and send files to others via e-mail.
4:To switch between portrait and landscape, use the button in the top right corner.

Feedback mail : OfficeReaderFeedback@gmail.com

OfficeReader

再谈Cocoa中回调delegate的方法时判断delegate是否已经被释放

我在Cocoa中回调delegate的方法时判断delegate是否已经被释放中描述了如何使用delegate的isa判断其所属类是否改变,从而判断delegate是否被释放。但是Nike指出:一旦此delegate注册过KVO,其isa就会被改变了。除非保证delegate不会被注册KVO(这要求判断delegate是否被释放时保证delegate必须是我们自己创建的,而不是其他任何人,而且我们要手工保证此delegate不会注册KVO),否则使用此种方法判断理论和实际上都是不可靠的。虽然iphone上的YAJL库目前也采用了这种方式判断对象类型,但是自从知道了KVO的那些事儿后,我觉得isa的方式还是很不靠谱的。

周末闲来无事读了读Objective-C Runtime Reference,发现objc的runtime中有两种判断类型的方式比较靠谱,他们可以直接取得任意一个objc_object(和id是完全一样的数据类型)的类或者类名。其函数如下:

//Returns the class name of a given object.
const char *object_getClassName(id obj);
 
//Returns the class of an object.
Class object_getClass(id object);

第一个函数可以返回任意一个id的类名,第二个函数可以返回任意一个id的Class。
而第二个函数会牵扯到isa-swizzling问题,参考八楼Nike大神的回复。
object_getClassName会不会牵扯到isa-swizzling问题我还没试过,没时间尝试~

以下为使用object_getClass判断delegate是否存在的一个例子,例子中MasterViewController将创建一个新线程试图回调DetailViewController的callback方法(涉及isa-swizzling,所以KVO下无效,但是下面例子的代码我没时间修改了)。
首先声明好用于回调的Protocol:

@protocol CallbackProtocol <NSObject>
 
@required
- (void)callback;
 
@end

然后在MasterViewController的成员变量里加上一个Class变量,用于存放delegate刚刚被设置进来时其Class:

@interface MasterViewController : UITableViewController
{
    __unsafe_unretained id <CallbackProtocol> _delegate;
    Class _originalClass;
}

在设置delegate的同时,将其Class保存在_originalClass成员变量中:

_originalClass = object_getClass(_delegate);

在回调时首先判断_delegate是否为空,若不为空再判断其类型是否改变,若类型已改变,则此对象已被释放(在Cocoa中回调delegate的方法时判断delegate是否已经被释放中已经有相关叙述)。

    if (_delegate != nil) {
        Class currentClass = object_getClass(_delegate);
        if  (currentClass == _originalClass)
        {
            [_delegate callback];
        }
        else
        {
            NSLog(@"orginal:%d present:%d - Not same class",(int)_originalClass,(int)currentClass);
        }
    }
    else
    {
        NSLog(@"Delegate is nil");
    }

若成员变量不保存Class类型而仅仅将其指针保存为int则性能更优。
刚刚提到object_getClass没有被手动声明的话编译时此函数会被warning。为此我们需要自己手动声明此函数。不管你写在哪,我是写在了.m里。
在用了object_getClass的.m的#import语句之下,@implemention语句之上,加上下面两句话:

//Returns the class of an object.
Class object_getClass(id object);

至此大功告成。
回调demo下载地址:git://github.com/OpenFibers/CallbackDemo.git,demo中首先由master view进入detail view,再由detail view返回master view,返回后开辟新的线程,新的线程在3秒之后判断detail view是否存在。

以上
–OpenThread

【翻译】iOS Tech Talk:Michael Jruewitz谈性能测试

转自:http://blog.yuzhuohui.info/?p=116

英文原文:http://oleb.net/blog/2011/11/ios5-tech-talk-michael-jurewitz-on-performance-measurement/

这篇文章的来源是iOS5 Tech talk在柏林站的演讲。演讲者是Michael Jruewitz

 

 

第一次翻译英文文章,欢迎提意见。

——————————————————————————

一个好的iOS app不光只是漂亮,设计优雅而已,同时它们应该启动快速,界面响应及时,并且可以有效得管理内存。在你的用户看到他之前,你应该用你的技术去判断和修复性能问题。让我们来学习一下性能损失清单并且把它应用到你的每一个应用程序中,否则你的app很可能会被你的用户扫地出门。

在这次大会中,Michael详细的讲解了如何用 Instrument来发现三种常常会遇到的性能问题。总的来说,我非常喜欢这次谈话。我回顾了之前关于Instrument的一些介绍,你必须看每个demo两三次才能入门。但是这次我清楚得感觉到我学了不少东西。

一般建议:

“最重要的测试性能问题的技术就是真正得去测试它,而不是猜测”

猜测往往不是优化性能的真确方法。如果你没有进行测试,去优化性能将会非常困难,所以以后你必须把它放在最重要的优先级。苹果已经提供了一个 Instrument工具去量化地测量你的app的各方面。

另一个重要的方面就是一定要在真实的场景下面去测试你的系统。如果你仅仅是让一个年轻的开发者在少量的甚至是没有数据的情况下进行测试,这样你能难遇到以后会困扰到用户的性能问题和内存泄漏。你应该用真实情况下的数据量去测试你的app,并且保证要测试到最坏的情况。毕竟,那些用你的app管理着大量数据和使用最多的往往是你最好的客户,你是不会想去得罪他们的。

Michael总结了下面3个方面性能上的特性:

    1. 启动快速/避免阻塞
    2. 最小量使用内存
    3. 高效绘图

用他的话来说,如果你优化了这些东西,那么你可能在性能良好的app的道路上前进了一大半了。

1. 快速启动

“问一下自己,这是加载主UI基本的操作吗?如果不是,那么放在后面做吧。”

许多iOS app启动一次要几秒钟(即使在多任务的情况下)并且经常出现重启。没有比这更加令人沮丧的了,用户没有必要为从程序启动到可以操作等待几秒钟的时间。

你的优化目标是让你的用户可以尽快操作app。这意味着一些UI组件(image或者web组件)还没有加载完是没问题的。这比让用户等到全部组件加载完成好得多了去了。

为了让启动用时最少,尽可能找出的那些你的ui准备就绪前必须调用的方法。

  • application:didFinishLaunchingWithOptions:
  • applicationWillEnterForeground:
  • applicationDidBecomeActive:
  • application:openURL:sourceApplication:annotation:
  • application:didReceiveRemoteNotification:
  • application:didReceiveLocalNotification:
  • init
  • awakeFormNib
  • viewDidLoad
  • viewWill/DidAppear:
  • application:didFinishLaunchingWithOptions:
  • viewDidLoad.

你应该注意到的最常见的问题是网络的同步请求和在一个线程中载入和解析大的数据或者图片。dispatch_async()方法是你最大的朋友。你不因该阻塞主线程的操作,因为有些同步操作可能需要花很长时间(几十秒),在程序启动阶段这个时间应该更短。尝试把这些操作放到后台队列中,当操作完成后去通知主线程队列。在那之前,你的用户界面上可以显示一个进度条。

Time Profiler工具

找出这类问题可以用“Time Profiler instrument”。在你的app运行的时候, instrument会不断得采样和记录在调用堆栈中代码的当前位置,从而确定花费最多时间的方法。

当你已经收集了足够多的数据,停止录制。现在你的目标是找到调用树中最耗时的方法,并且逐一去优化它们。这里有一些Michael的建议:

    • 在录制的过程中,在时间轴上放置些标记来明确一些重要的时间点,比如说启动结束的时候。
    • 在查看调用树之间,先用工具栏上的按钮确定检查范围。用在录制时设定的标记来确定你想要分析哪部分的代码。
    • 取消”invert call tree”和”Hide System Libraries”两个选项。前面那个使调用树更容易被人理解(即使这需要花费一点时间去点击一些没用的方法),后面那个选项可以显示系统框架的耗时。如果你隐藏它,那么你可能忽视了一个会造成你app启动时间增加的同步的网络请求。

    • 现在是时候来探究一下调用树了。他从main()开始,通过展开你自己的树直到找你你自己的代码(通常会在大于10层的深处)并且尝试去找出那些耗时较多的方法。打开详细试图可以看到关于选中行的更多的信息,或者双击其中一个方法可以直接跳转到xcode中查看你的代码。

    • 需要特备注意下 Self 列。它会告诉你在方法内部实际到底需要话多少时间而不是在堆栈中被这个方法调用的进行下去的时间。一个在 Self 中占用百分比比较大的往往指出了你代码中的问题,比如一个比较长的循环。
    • 经验之谈:最好你的app启动的时候最多只需要2-3秒钟。如果你自己的代码在总的启动时间中占用20-30%,那么这就可能存在问题了。

2. 合理使用内存

内存占用的优化是从一个开是伴随着iOS开发者的。因为iOS设备没有交换文件,所以一个app内存使用是受到硬件限制的。如果app需要的内存比可用的内存要多,那么OS只能杀掉一些app的进程,这些工作都是在后台来做的。还有一个促使我们使用更少内存的原因:如果你的app使用的内存更少,那么OS会让你的app待在后台的时间更长,那就意味着可以带给用户更好的体验。

“在iOS5中,如果你的程序是在最上层的而我们向你发了一个内存警告,那么就意味着你的头已经被放在砧板上了。”

OS可以向一个正在使用中的app发送一个内存警告来告诉你内存使用压力。Michael指出在iOS4中引入多任务,很多app懒得去处理一个内存警告。毕竟,如果一个前台的程序当接到内存警告的时候没有做任何处理,OS是不会杀掉他的进程的,而运行在后台的一些app是首先会被杀掉的。这确实是iOS4的行为。由于这些意想不到的后果,Michael强调道Apple已经在iOS5中做了改变:“在iOS5中,如果你的app是正在使用中的app,如果我们发一个内存警告给你。这就意味这你的头已经给放在案板上了(我想这是说,OS会杀掉这个前台程序的进程而不是后台的程序进程)”。所以你最好处理好内存警告。

Instruments: Allocations + Leaks + VM Tracker + Activity Monitor

Michael给出了他自己用 instrument工具组合来测试app的方法。 Allocations,Leaks, VM Tracker 和Activty Monitor 测量工具。对你来说很容易创建一个空白的 instrument,然后从 Library inspector 面板拖动这四个监视工具到主窗口。可以保存这个 instrument为模版,以后打开就直接可以用了。

Activity Monitor可以用来比较你的app的和在后台运行的app的资源使用情况。打个比方,用 Real Memory 来对app进行排序然后选择 Track inspection head。现在,当你拖动刚刚录制的时间轴箭头,你可以看到你自己的app会在这些程序中根据内存的使用量上升(或者下降)。

Allocations instruments会产生误导,因为他不会显示你的app所有的内存使用情况(只会显示malloc类型的内存分配)。但是,你仍然应该关注一下下面的几种情况:

    • 一个不断增长的内存分配图表显然不是一个好现象。这通常表明有些相当严重的内存泄漏。如果你不去解决这些问题,那么你的程序可能会崩溃,因为它迟早会耗尽所有的内存。
    • 如果你在你的app中不断重复同样的动作(例如,切换到一个画面然后回到前一个画面),你的内存使用量不应该增加。在内存分配图表中你常常会看到这样的现象,在你开始进入下一个页面的时候内存有所增加(因为你创建了一个新的视图),回到前一个页面后内存有所减少,尤其是在反复多次操作的时候。
      如果你发现没有或者仅仅一部分内存被回收,这表示泄漏或者废弃了某一块内存,造成这个结果的的可能是被循环retain了。用Instrument的Heapshot可以分析和追踪这些问题。通过标记堆之间的重复动作,Instruments可以告诉你哪些对象没有被释放。查看这些列表通常可以把你引向正确的轨道。
    • 大量的内存使用会造成系统把只读的页面从内存中去掉,因为操作系统知道这些东西可以以后从磁盘中读取。由于你的app的代码也是这些可以再次载入的只读页面的一部分,那么当内存使用量在达到极限的时候可能会在系统重新载入的你app代码的时候停顿一下。尽量去避免这样的事情出现,你可以的。

“VM Tracker,提供了你的app内存使用量最准确的图表。”

VM Tracker 可以显示你的app内存使用量最正确的统计,所以它非常有用。 “Resident Size” 和“Dirty Size”这两列可以分别被映射到磁盘和无法被回收的内存数量。根据Michael的说法, “Dirty”行和“Resident”列最真实的反映了你的app在在时间轴上的某个时间点的内存使用量。所以不要因为这个数值在这里显示的和Allocation instrument上显示得完全不一样感到迷惑。

3.高效绘图

“经验之谈:如果在一个屏幕上超过一半的区域用了透明层,那么滑动起来很可能变得卡了。”

Core Animation instrument可以帮你找出你的绘图代码产生的性能问题。通过把你的layer的颜色显示出来,你很快可以发现你到底做了什么。

即使你的app UI全部是用UIKit来控制的,并且你也没有自己绘制任何内容,也是很有可以对性能造成明显影响的,尤其是当滚动的时候。Michael说,你应该尤其注意下面几点:

    • 透明过度:绘制透明对GPU来说困难多了,所以你应该尽可能避免使用透明。当然啦,很多好的效果是需要用到透明的,比如投个阴影到边缘和圆角,但是最终你的用户会更加喜欢那些滚动起来流畅的app而不是那些只是漂亮了一点点但是滚动起来一卡一卡的app。
      Michael尤其强调了在自定义的table cell中构建text Label的情况。大多情况下Label可以保持一个不透明的固定的背景色,因为当cell被选中的时候table view会自动转换背景色。如果你必须要使用透明,至少要保证两个透明的label不要重叠(这样的话GPU需要增加成倍的工作)。
      Core Animation instruments会标记透明的图层为红色,不透明的为绿色。
    • 绘制缩放的内容:缩放图片会造成图形系统额外的工作,我们可以通过使用正确大小的资源文件来避免。如果你的app显示的内容是从网上下载的的,那么可以通过程序下载需要显示的正确大小的图片。
      Core Animation instrument会用黄色突出显示缩放过的内容。并不是所有的缩放都是不好的。Core Animation instrument也会标记许多UIKit中的元素为黄色,比如navigation bar和tab bar。 因为它们使用了拉伸的图片作为他们的背景,这是没问题的。
    • 绘制像素坐标:虽然Core Graphics的坐标使用了浮点,在显示前这些坐标要映射到设备固定的像素网格上。确保你需要绘制的内容的坐标是正数的,这样可以避免在显示的时候造成重叠,不然的话不但会造成性能问题(浮点计算比较费资源),同时也会使你的app看起来很糟糕。Core Animation instrument会把没有对齐的内容标记成洋红色。

UIAlertView 自动消失 和 动态修改

很多人以为UIAlertView是要点击取消或其他按钮才可以消失的,其实不是,可以用代码触发这个动作~

[loadingAlertView dismissWithClickedButtonIndex:0 animated:YES];

 

动态修改当前的UIAlertView的对象,其实方法很简单,取到它改就成咯~我是自定义了一个LoadingAlertView继承自UIAlertView。然后进行相关操作。

在生成LoadingAlertView的时候,如果你想修改UIAlertView内的布局,就在下面的方法修改。

- (void)layoutSubviews {
 
[super layoutSubviews];
 
//你要写的内容
 
}

如果你想添加一些自己的空间,比如UIImageView,UISwitch等,可以写在初始化方法里面,我是这样做的~

- (id)initWithFrame:(CGRect)frame {
 
if (self = [super initWithFrame:frame]) {
 
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
 
activity.frame = CGRectMake(180, 15, 80, 80);
 
[activity startAnimating];
 
[activity sizeToFit];
 
[self addSubview:activity];
 
}
 
return self;
 
}

如果需要动态修改,就写一个方法,让外部来调用,如下~

方法:

- (void)loaded {
 
for (id obj in self.subviews) {
 
if ([obj isKindOfClass:[UILabel class]]) {
 
UILabel *label = obj;
 
label.text = @"加载完毕";
 
label.textAlignment = UITextAlignmentCenter;
 
}
 
else if ([obj isKindOfClass:[UIActivityIndicatorView class]]) {
 
[obj stopAnimating];
 
}
 
}
 
}

调用:

[loadingAlertView loaded];

下面看效果图吧~

代码在https://github.com/juxuechen/AlertPickerView/tree/dismissAlert 这里,欢迎关注~~~

xcode的代码标记功能

原文链接:http://blog.yuzhuohui.info/index.php/2011/11/05/xcode-code-tag/

xcode在代码中可以加一些标记,使查找更加方便。

#error FIXME: fix now!
#warning TODO: fix this later...
这两个标记会像普通的警告和错误出现在代码左侧,如果有#error编译也是不能通过的。
//MARK: Like #pragma mark
//TODO:
//FIXME:
//???:
以上四个标记会出现在jump bar上。必须写在方法外面。
当然还有一个常用的#pragma mark

无痛使用arc

原文链接:http://blog.yuzhuohui.info/?p=78
伴随这iOS5的发布,xcode中加入了一个振奋人心的新特性:ARC(Automatic Reference Counting,俗称自动引用计数)

图片来源:http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html

开启了这个特性之后,我们就不用在管理内存了。llvm3.0在编译期会自动把retain神马的加上。这就省去了很多麻烦事儿,可以把更加多的精力放在功能的实现上。

如何开启arc:

在创建项目的时候开启arc:

在创建完后开启arc:

在target的bulid setting中找到objective-C Automatic Reference Counting,选择YES:

如何让没有使用ARC的代码和使用了ARC的代码共存?

目前很多开源的框架,和我们之前写的代码中,都是手动管理内存的。代码中有很多retain,release,autorelease等和内存管理相关的代码。如果开启了arc特性后,xcode在没有就会报错。一个办法是手动把这部分的代码去掉,同时还要加各种__unsafe_retained之类的标记。这将是一个繁重的体力活。

其实我们llvm3.0中支持手动管理内存的代码和使用arc技术的代码共存的。

首先,需要开启arc特性。

然后我们可以告诉编译器那些代码没有使用arc。

具体操作如下,在target的bulid phases中展开compile source s中为不需要arc的代码加上-fno-objc-arc的参数。

上图就是我在一个arc的工程中加入了ASIHttpRequest。

如果想Three20这样添加框架的方式,可以不用设置这个参数,因为是用proj之间的依赖。

iOS sqlite控件 Sqlight

引用链接:http://jiajun.org/2011/09/30/ios_sqlight.html
记:上一篇文章介绍了Kache这个缓存控件,可以用来配合这次iCloud升级,这篇是关于一个sqlite的封装,Sqlight,一个很轻量级的封装,也是为了配合iCloud。模仿了PHP mysql扩展PDO的一些做法。把数据库操作封装成方法,通过NSDictionary和NSArray传递参数。源码:http://jiajun.org/g/Sqlight.zip

Sqlight真是没什么可介绍的,主要的常用方法有4个,select, update, insert和delete,还有一个create table在初始化时调用。用法示例在 Sqlite.h 文件的注释中。

简单介绍一下原理,Sqlight的数据文件是放在Documentation目录的,也就是说会被备份到iCloud。跟cache不同,我建议在数据库里存放一些比如,用户信息,登录状态等等。

以下把用法示例贴一下:

SqlightAdapter *sqlight = [[Sqlight alloc] initWithDatabase:@"test_database"
						AndTable:@"test_tb"];
 
if (nil == sqlight) {
	sqlight = [[Sqlight alloc] initWithDatabase:@"test_database"];
 
	[sqlight createTable:@"test_tb" Info:[NSArray arrayWithObjects:@"f1", @"f2", nil]];
	sqlight.tableName = @"test_tb";
}
 
[sqlight insertData:[NSDictionary dictionaryWithObjectsAndKeys:
					 @"value1", @"f1",
					 @"value2", @"f2",
					 nil]];
 
// this is a wrong condition, there is no f0 field.
sqlight_result_t res = [sqlight selectFields:[NSArray arrayWithObjects:@"f1, f2", nil]
						ByCondition:@"f0=?"
						Bind:[NSArray arrayWithObjects:@"value1", nil]]; 
 
NSLog(@"%d -- %@ -- %@", res.code, res.msg, res.data); // will out put 1 -- no such column: f0 -- ()
 
res = [sqlight selectFields:[NSArray arrayWithObjects:@"f1, f2", nil]
					ByCondition:@"f1=?"
					Bind:[NSArray arrayWithObjects:@"value1", nil]]; 
 
NSLog(@"%d -- %@", res.code, res.data); // will out put 101 -- ( value1, value2 )
 
[sqlight updateData:[NSDictionary dictionaryWithObjectsAndKeys:@"value_new", @"f1", nil]
					ByCondition:@"f1=?"
					Bind:[NSArray arrayWithObjects:@"value1", nil]];
 
res = [sqlight selectFields:[NSArray arrayWithObjects:@"f1, f2", nil]
					ByCondition:@"f1=?"
					Bind:[NSArray arrayWithObjects:@"value1", nil]]; 
 
NSLog(@"%d -- %@", res.code, res.data); // will out put 101 -- ()

iOS缓存控件 Kache

引用连接:http://jiajun.org/2011/09/30/ios_kache.html

记:昨天(Sep. 29)想必很多 iOS 开发者都收到Apple的邮件和苹果中国的工作人员的电话了,要求开发者升级应用,调整本地文件的存储位置,以适应即将发布在iOS5中启用的iCloud同步应用数据功能。恰好我这里有n久以前写的一个缓存控件(Kache的源码:http://jiajun.org/g/Kache.zip),现在再拿出来,希望在这次大规模的升级中,能给大家带来方便。

Kache 的基本思路是:用一个单例对象hold住整块内存,每次set都把数据set到这块内存里,get也从这里拿。在需要持久化的时候,例如程序退出之类的,调用一个saveToStorage方法,把这块内存持久化,存到iCloud文档中提到的Caches目录,这个目录是不会被iCloud备份的。在需要从本地存储载入时调用一个loadFromStorage方法,把整块内存load出来,照常使用。注意:Kache只能缓存 NSData, NSDictionary, NSArray, NSString等这些基本数据结构,不能缓存其他对象。

Kache提供两个基本功能:

1,普通缓存,允许设定有效时长,如果用户不指定被缓存数据的有效时长,则默认为86400秒,也就是一天过期。

2,缓存队列,Kache提供一个队列,用户可指定队列长度,默认为100,当新数据进入缓存队列导致队列长度超过100时,最先进入的数据会被删除。普通缓存不影响队列。

特殊需求:

之前提到,Kache使用的是一个单利hold住整块内存,那么一个单例中只允许有一个缓存队列。如果需要多个缓存队列,那么可以使用Kache提供的实例方法,开发者自己创建单例对象来hold住不同的内存。

基本用法:

用法非常简单,只要 #import “KCH.h”后,就可以按照 KCH.h 文件注释的例子来调用缓存了。

阅读源码:

Kache的源码非常简单,只有6个文件加1个KCH.h。

KCH.h基本上是一个README作用的文件。

KCHObject.h/KCHObject.m 定义了缓存的原子对象,这里记录了某个数据的过期时间和具体数据等内容。

KCHHolder.h/KCHHolder.m 定义了整个缓存的基本操作方法,包括对过期的处理,对队列的处理,持久化,重置等等。

Kache.h/Kache.m 是对KCHHolder的封装,提供了所有操作的实例/静态方法,以及对一直说到的单例的定义。

【译】App Store Review Guidelines for iOS Apps

引用链接:http://jiajun.org/2011/09/22/app_store_review_guidelines_for_ios_apps.html

iOS应用商店审核指南

译者注:翻条款类的文档太尼玛折磨了。。。3000多字总算折腾完了,里边可能有一些不像人话的地方,请指出,我肯定虚心接受,择机改正。文档里可能有好多错别字,我会慢慢发现纠正的~~~祝大家开发快乐!

原文链接在这(需要IDP登陆):http://developer.apple.com/appstore/guidelines.html

简介

非常高兴您能付出宝贵的时间和精力来开发iOS应用。成千上万的开发者的经历表明,无论从专业技术还是经济收入上,开发iOS应用都是个不错的选择,我们将协助你你更快的成为其中一员。这篇App Store Review Guidlines主要是为了协助你弄清楚开发过程中会遇到的一些疑惑,加快你提交应用的审核过程。

我们认为应用不同于书籍和歌曲,我们不支持这些。如果你要讨论宗教信仰,那么应该去写书。如果你要谈论性,那么写书,或者去写歌,或者去做一个生理卫生的应用。看起来可能有点烦人,但我们仍然决定App Store不接受上述内容。记住下边这些原则,会对你有所帮助:

有很多小孩子会来商店下载应用,而且除非父母们设置了家长管理(事实很多人不设置),否则孩子们是不受任何限制的。所以我们要关注孩子们。

现在商店里有超过350,000个应用。我们不需要一个款差劲的应用。一款不能提供一些有用的功能,或者只是哗众取宠的恶作剧的应用,肯定通不过审核。

如果你的应用一看就是一个三两天拼凑出来的东西,或者你只是想把一个练手应用上到商店里,跟朋友秀一把,那在被拒以后一定要hold住。我们有大批严肃的开发者,不希望高质量应用与这些残次品为伍。

我们会拒掉那些,有越线内容或行为的应用。那么红线是什么呢?子曾经曰过:“等真见到的时候,我才知道”。还有,我们相信你越线的时候,你也会知道的。

我们提供一个审核版,如果你的应用被拒了,你可以在那上诉。不过你威胁我们,或者乱喷,肯定是于事无补的。

如果你试图蒙骗系统(比如:在审核过程中做手脚,盗取用户数据,剽窃其他开发者作品,或者刷评级),你的应用会被下线,开发者身份也会被取消。

这是一篇动态文档,新应用随时都会带来新的规则,你的应用可能就带来下一条规则。

最关键的是,我们非常珍视这个平台,并且尊重您的作品。我们真心要创造一个全球最好的平台,在这里你们可以大展才华,并且以此为生。看起来我们限制了太多的东西,恩,其实是因为,我们承诺用户,他们在apple的设备上享有最佳体验。就像你们也希望的那样。

目录

1.     条款与条件

2.     功能

3.     元数据,评级与分类

4.     位置

5.     提醒推送

6.     游戏中心

7.     iAds

8.     商标权与商品外观

9.     媒体内容

10.   用户接口

11.   购买与传播

12.   废弃与聚合

13.   损坏设备

14.   个人攻击

15.   暴力

16.   负面内容

17.   隐私

18.   色情

19.   宗教,文化和种族

20.   竞猜,赌博,彩券和抽奖

21.   慈善与捐助

22.   法律条件

 

1. 条款与条件

1.1 作为App Store的应用开发者,你受限于如下条款:Program License Agreement (PLA),Human Interface Guidelines (HIG),以及任何你与apple签订的协议和证书。以下规则和示例是为了协助你的应用更快通过审核上架,而不是修正或取代之前的条款。

 

2. 功能

2.1   存在崩溃的应用会被拒。

2.2   存在明显bug的应用会被拒。

2.3   不符合开发者描述的应用会被拒。

2.4   有未说明或隐藏特性或有悖描述的应用会被拒。

2.5   使用非公开API的应用会被拒。

2.6   试图读写非允许范围内的数据的应用会被拒。

2.7   试图以任何方式方法下载代码的应用会被拒。

2.8   安装或运行其他可执行代码的应用会被拒。

2.9   任何“beta”,“demo”,“trial”或“test”版本的应用会被拒。

2.10 iPhone应用必须可以无条件运行在iPad上,支持普通iPhone分辨率和2倍iPhone 3GS分辨率。

2.11 任何与App Store中上架应用重复的应用会被拒,尤其是已经有了很多的:如放屁,打嗝,照明和爱经。

2.12 没有用处的应用,web页面简单组合的应用,或任何哗众取宠,不能提供持续价值的应用会被拒。

2.13 用于市场推广或广告的应用会被拒。

2.14 有意提供隐蔽或虚假功能,却又不能明显标示的应用会被拒。

2.15 大于20MB的应用无法通过蜂窝网络下载安装(App Store自动处理)。

2.16 多任务应用只允许在后谈运行如下服务:VoIP,音频播放,地理位置,任务记录,本地提醒等。

2.17 应用只允许通过iOS WebKit框架和WebKit Javascript访问web页面。

2.18 鼓励酗酒,使用违法药物,或诱导未成年人饮酒,吸烟的应用会被拒。

2.19 提供错误的系统信息或设备数据的应用会被拒。

2.20 通过许多版本的类似应用对App Store造成干扰的开发者会被取消IDP身份。

2.21 歌曲和电影应该提交到iTunes store。书籍应该提交到iBookstore。

2.22 随意通过位置或设备限制用户使用的应用会被拒。

 

3. 元数据(名称,描述,评级,分类等)

3.1   应用或者元数据中提到其他任意移动平台会被拒。

3.2   元数据有未填写项,存留占位符文本会被拒。

3.3   描述中提到与应用内容和功能无关信息会被拒。

3.4   应用在iTunes Connect与设备上显示的名称应该类似,否则会造成混淆。

3.5   不同尺寸的icon要一致,否则会造成混淆。

3.6   图标与截屏不符合4+年龄评级的应用会被拒。

3.7   应用的内容与所选分类和风格不符会被拒。

3.8   开发者有责任把应用放到恰当的评级。不恰当的评级可能会被Apple修改,甚至删除。

3.9   开发者有责任给应用撰写恰当的关键词。不恰当的关键词可能会被Apple修改,甚至删除。

3.10 通过伪造,付费评价或其他非正规手段,获取App Store中较好的评价与星级的开发者会被取消IDP身份。

3.11 任何提示需要用户重启iOS设备来安装或运行的应用会被拒。

3.12 应用在提交审核过程中,所有涉及到的URL都要处于正常运行状态,例如保密协议,相关支持页面等。

 

4. 位置

4.1   未提示用户且获得用户允许之前手机,传输或使用位置数据的应用会被拒。

4.2   使用location-based API来自动控制车辆,飞行器或其他设备的应用会被拒。

4.3   使用location-based API进行调度,队伍管理或应急服务的而应用会被拒。

4.4   位置数据只能用于应用提供的直接相关功能或服务,或者有授权的广告。

 

5. 提醒推送

5.1   不使用APN API提供消息推送的应用会被拒。

5.2   使用APN服务却没从Apple获取一个Push Application ID的应用会被拒。

5.3   在首次推送消息之前取得的用户允许的应用会被拒。

5.4   使用提醒推送服务推送敏感的个人或机密信息的应用会被拒。

5.5   使用提醒推送发送主动消息,欺骗或干扰信息的应用会被拒。

5.6   应用不可以使用提醒推送发送广告,活动或任何形式的直接推广信息。

5.7   应用不可以提供收费的提醒推送服务。

5.8   使用APN服务过度占用网络带宽或容量或通过提醒推送大量占用系统资源的应用会被拒。

5.9   传输病毒,文件,代码或程序,导致破坏或扰乱正常的APN服务操作的应用会被拒。

 

6. 游戏中心

6.1   向终端用户或第三方展示Player ID的应用会被拒。

6.2   Player ID被用于Game Center条款款意外的用途的应用会被拒。

6.3   试图通过Game Center反查,跟踪,描述,关联,发掘,收割,或利用Player ID,别名或其他信息的开发者会被取消IDP身份。

6.4   Game Center信息,例如Leaderboard得分,只能通过Game Center用于应用中。

6.5   使用Game Center发送主动消息,欺骗或干扰信息的应用会被拒。

6.6   使用Game Center过度占用网络带宽或容量的应用会被拒。

6.7   传输病毒,文件,代码或程序,导致破坏或扰乱正常的Game Center操作,的应用会被拒。

 

7. iAds

7.1   人工刷广告浏览或点击率的应用会被拒。

7.2   带有空iAd横幅的应用会被拒。

7.3   设计主要用来展示广告的应用会被拒。

 

8. 商标权与商品外观

8.1   应用必须遵守Guidelines for Using Apple Trademarks and Copyrights 和Apple Trademark List中描述的所有条款和条件。

8.2   任何误导或暗示Apple为该应用来源或提供商,或Apple以任何形式认可其质量或功能的应用会被拒。

8.3   外观与现有Apple产品或广告主题类似或混淆的应用会被拒

8.4   应用名称中出现错误的Apple产品拼写(如,GPS for IPhone, iTunz)的应用会被拒。

8.5   使用受保护的第三方资源(商标,版权,商业机密,以及其他私有内容),请提供一份文本形式的使用授权。

8.6   在保证原有内容的商标特征不被覆盖且完全可见的前提下,应用可以通过Google Maps API调用Google Maps和Google Earth图片。任何遮盖或修改Google标志或版权人证明的应用会被拒。

 

9. 媒体内容

9.1   使用MediaPlayer框架意外的方法访问Music Library中媒体数据的应用会被拒。

9.2   用户界面模仿任何iPod界面的应用会被拒。

9.3   通过蜂窝网络传输的流媒体音频内容不得超过5MB或多余5分钟。

9.4   通过蜂窝网络传输超过10分钟流媒体视频内容,必须使用HTTP Live Streaming,并包涵一条基线64kbps的音频HTTP Live流。

 

10. 用户界面

10.1  应用必须遵守Apple iOS Human Interface Guidelines中的条款和条件。

10.2  外观与iPhone自带应用(如:App Store,iTunes Store和iBookstore)相似的应用会被拒。

10.3  不按照Apple iOS Human Interface Guidelines中的描述正确使用系统控件的应用会被拒。

10.4  试图创建多桌面/主屏环境或模拟多应用工具的应用会被拒。

10.5  修改硬件开关标准功能(例如:音量,震动)的应用会被拒。

10.6  Apple和我们的用户都界面报以很高期望,希望他设计的超级简洁,精致,充满创造力,深思熟虑。做到这些确实会消耗很多精力,但是值得。Apple在这方面要求非常高。如果你的用户界面过于复杂,甚至仅仅是不够好,都可能被拒。

 

11. 购买与流通

11.1  通过App Store以外的渠道解锁或开启附加属性或功能的应用会被拒。

11.2  使用In App Purchase API (IAP)意外的系统提供购买内容,功能或服务的应用会被拒。

11.3  使用IAP为与应用无关的实体商品或商品服务收费的应用会被拒。

11.4  应用使用IAP为信用账户或其他货币收费,必须在应用中消费。

11.5  使用IAP向过期的信用账号或货币收费的应用会被拒。

11.6  使用IAP收费订阅的内容至少要在7天内有效,而且允许在所有iOS设备间共享。

11.7  用到IAP收费项目的应用必须分派到正确的收费类目中。

11.8  使用IAP向用户收费以获取iOS内建功能(如摄像头,陀螺仪)的应用会被拒。

11.9  包涵“出租”内容或服务的应用,在有效期后会被拒。

11.10 保险类应用必须免费,遵守发布地区的法律,不允许使用IAP。

11.11 一般来说,越贵的应用审核就越彻底。

11.12 提供收费订阅的应用必须使用IAP,Apple将会按照Developer Program License Agreement中约定的70/30的比例与开发者分账。

11.13  应用中如果提供了IAP以外的收费或订阅机制,如:“buy”按钮,跳转到一个购买电子书的web页面,会被拒。

11.14  应用可以阅读或播放任何在应用以外取得授权的内容(包括指定的杂志,报纸,书籍,音频,音乐和视频),但在应用中不允许出现获取授权的收费链接或按钮。Apple不会对在应用外订阅或购买授权项目收取任何费用。

 

12. 抓取与整合

12.1  从Apple的页面(如:apple.com, iTunes Store, App Store, iTunes Connect, Apple Developer Programs, 等)抓取内容,或利用Apple页面和服务中的内容进行排名的应用会被拒。

12.2  应用可以使用授权的Apple RSS,例如iTunes Store RSS。

12.3  简单的web页面裁剪,内容整合或链接收集应用会被拒。

 

13. 设备损害

13.1  任何怂恿用户做出可能损坏Apple设备的行为的应用会被拒。

13.2  快速耗光设备电力或产生大量热量的应用会被拒。

 

14. 人身攻击

14.1  任何涉嫌诽谤,侮辱,狭隘内容或打击个人或团体的应用会被拒。

14.2  职业政治讽刺家和幽默作家不受该条款约束。

 

15. 暴力

15.1  展示人或动物被杀戮,致残,枪击,针刺或其他伤害的真实图片的应用会被拒。

15.2  描述暴力或虐待儿童的应用会被拒。

15.3  游戏中的“敌人”不能单独的设定为某特定比赛,文化,真实的政府或组织,或者任何现实事物。

15.4  含有以鼓励非法或鲁莽使用的方式描述真实武器的应用会被拒。

15.5  带有俄罗斯轮盘游戏的应用会被拒。

 

16. 三俗内容

16.1  介绍过度三俗和粗鲁内容的应用会被拒。

16.2  设计来惹怒或恶心用户的应用会被拒。

 

17. 隐私

17.1  在未获得用户事先允许,或未告知用户信息将被如何,在哪里使用的情况下,应用不可以传输用户数据。

17.2  要求用户提供个人信息,如邮箱地址,生日等,才能使用其功能的应用会被拒。

17.3  专门收集未成年人数据的应用会被拒。

 

18. 色情

18.1  含有韦氏词典中定义的色情素材(explicit descriptions or displays of sexual organs or activities intended to stimulate erotic rather than aesthetic or emotional feelings),的应用会被拒。

18.2  经常有用户提供色情内容(例如:Chat Roulette http://en.wikipedia.org/wiki/Chatroulette )的应用会被拒。

 

19. 信仰,文化和种族

19.1  带有对一种信仰,文化或种族进行诽谤,侮辱,狭隘,或以他们为目标的暴力或伤害内容的应用会被拒。

19.2  应用若带有或应用对一种信仰的文字描述,那么这个引用或翻译必须是精确,无歧义的。注释内容可以具有教育性,信息性,但不可以为煽动性。

 

20. 竞赛,赌博,彩票和抽奖

20.1  赌博和竞赛必须是由应用开发者或所有公司发起的。

20.2  应用中必须展示赌博和竞赛的官方条款,并声明Apple不是发起者,并且在任何情况下与此事无关。

20.3  开发者必须经过法律允许才能上线一款抽奖应用,而且抽奖应用必须具备以下要素:报酬,机会,和奖金。

20.4  直接允许用户在应用中购买彩票或抽奖的应用会被拒。

 

21. 慈善与捐助

21.1  含有向已认证的慈善机构捐助功能的应用必须是免费的。

21.2  慈善募捐必须通过短信息或通过Safari访问web页面完成。

 

22. 法律要求

22.1  应用必须遵守所有发布地区当地法律。开发者有义务了解和遵守各地的法律。

22.2  任何带有虚假,欺诈和带有歧义的描述的应用会被拒。

22.3  任何召集,推销和股东犯罪和鲁莽行为的应用会被拒。

22.4  非法文件共享应用会被拒。

22.5  任何设计用来非法赌博,包括算牌,的应用会被拒。

22.6  提供匿名电话或短消息/彩信功能的应用会被拒。

22.7  任何开发暗中获取用户密码和私有数据的开发者会被取消IDP身份。

22.8  任何非法律执行部门发布的带有DUI检查点信息,或鼓励且协助酒后驾车的应用会被拒。

 

动态文档

撰写这篇文档,表示我们尽全力与您分享我们是如何审核提交到App Store的应用的,而且我们希望这个指南能够对您开发和提交应用有所帮助。这是一份动态文档,我们将根据新近应用和情况定期更新这篇文档。

感谢您为iOS开发应用。尽管这是一份“禁止”列表,但请谨记那份更短的“必做”列表。最重要的是,加入我们就是要给用户带来惊喜和愉悦。把世界用最具创意的方式展示给他们,让他们以前所未有的方式生活。根据我们的经验,用户真的会对功能和界面上的改进有所反应。进一步改进你的作品。带给用户超出期望的体验。带给用户前所未有的体验。我们将协助您完成这一切。

© Apple, 2011

 

←Older