标签: IOS开发

iOS开发去面试BAT,这些iOS面试题必须得会

前言
*近把各个大厂的 iOS面试题整理了, 题目大部分是网上收录的, 方便自己巩固复习, 也分享给大家; 希望对大家有所帮助!

此次iOS面试题 ,底部会提供一份答案
题集大全
1: 谈谈你对KVC的理解

2: iOS项目中引用多个第三方库引发冲突的解决方法

3: GCD实现多读单写

4: 讲一下atomic的实现机制;为什么不能保证*对的线程安全?

5: Autoreleasepool所使用的数据结构是什么?

6: AutoreleasePoolPage结构体了解么?

7: iOS中内省的几个方法?

8: class方法和objc_getClass方法有什么区别?

9: 分类和扩展有什么区别?可以分别用来做什么?

10: 分类有哪些局限性?分类的结构体里面有哪些成员?

11: 能不能简述一下Dealloc的实现机制

12: HTTPS和HTTP的区别

13: TCP为什么要三次握手,四次挥手?

14: 对称加密和非对称加密的区别?分别有哪些算法的实现?

15: HTTPS的握手流程?为什么密钥的传递需要使用非对称加密?双向认证了解么?

16: 如何用Charles抓HTTPS的包?其中原理和流程是什么?

17: 什么是中间人攻击?如何避免?

18: 了解编译的过程么?分为哪几个步骤?

19: 静态链接了解么?静态库和动态库的区别?

20: App网络层有哪些优化策略?

21: 排序题︰冒泡排序,选择排序,插入排序,快速排序(二路,三路)能写出那些?

22: iOS开发中的加密方式

23: App安全,数字签名,App签名,重签名

24: OC数据类型

25: property和属性修饰符

26: 成员变量ivar和属性property的区别,以及不同关键字的作用

27: 类簇的优缺点

28: 谈谈设计模式

29: 谈谈架构设计

30: ReactiveCocoa的使用及优缺点

31: 类的继承,类能否多继承,协议能不能做继承?

32: 分类(category)和类扩展(extension)的区别

33: 如何实现week

34: 字典注意事项:setvalue和setobject的区别

35: 多线程和锁

36: WebSocket与TCP Socket的区别

37: 事件传递和响应机制

iOS开发中总结的小技巧(持续更新中)

1、设置导航栏

//设置导航栏
//#MARK: 背景颜色
UINavigationBar.appearance().barTintColor = UIColor(red: 33/255, green: 150/255, blue: 243/255, alpha: 0.5)
//导航栏图标颜色
UINavigationBar.appearance().tintColor = UIColor.whiteColor()
//导航栏上的titleView字体
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor()]

self.navigationItem.backBarButtonItem = UIBarButtonItem(title: “”, style: .Plain, target: nil, action: nil) //返回按钮文字空

2、设置工具栏

//设置工具栏
UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName : UIColor.blackColor(), NSFontAttributeName : UIFont.systemFontOfSize(12)], forState: .Selected)

UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName : UIColor.grayColor(), NSFontAttributeName : UIFont.systemFontOfSize(12)], forState: .Normal)

3、初始化变量的写法

//初始化变量的写法
private var tableView: UITableView = {
let tableView = UITableView(frame: CGRectMake(0,0,UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height), style: UITableViewStyle.Plain)
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
return tableView
}()

4、UITableView和UICollectionView中的返回cell或者item个数回调方法的写法

//tableView or collectionView number
//return optional ?? 0//空合运算符

5、iPhone 各种型号屏幕的宽和高

//iphone 5s屏幕宽和高 320/568
//iPhone 6和6s屏幕宽和高 375/667
//iPhone 6plus和6splus屏幕宽和高 414/736

6、统计代码行数(在项目目录下)

find . -name “*.swift” |xargs wc -l

 

WIN10下的ios开发

电脑原生系统:Windows10,基于此,需要以下软件和环境:

Ø VMware Workstation Pro v15.0.0

Ø 解锁工具Unlocker v3.0.0

Ø macOS Mojave 10.14懒人版

Ø Xcode9.4.1

Ø swift 4.1.2

VMware Workstation+macOS配置,参见:
https://www.52pojie.cn/thread-804000-1-1.html
※注意:macOS安装完成后务必在Vmware上方“虚拟机”选择安装Vmware tools
内存配置见下图

%title插图%num

安装Xcode

Ø Xcode版本:9.4.1 (为了兼容macO,选择稍老版本的Xcode)

Ø 编程语言版本:swift 4.1.2 (Apple.Inc 自主研发的面向Apple开发的语言)

*,在win系统下去苹果官网[1]下载Xcode 9.4.1(旧版本,不然不兼容虚拟机上的mac版本)
https://developer.apple.com/download/more/
搜索栏搜索Xcode

※ 可将文件下载到WIN系统中,然后利用VMtools的功能直接将文件拖入虚拟机的macOS桌面上,完成安装。

%title插图%num
如此,即可在WIN10的环境下开发ios程序。

ios开发瀑布流框架的应用

一:瀑布流框架的应用:将封装好的瀑布流框架导入,遵守协议

二:代码:

  1 #import "HMShopsViewController.h"
  2 #import "HMShopCell.h"
  3 #import "HMWaterflowView.h"
  4 #import "HMShop.h"
  5 #import "MJExtension.h"
  6 #import "MJRefresh.h"
  7 
  8 @interface HMShopsViewController ()<HMWaterflowViewDataSource, HMWaterflowViewDelegate>
  9 @property (nonatomic, strong) NSMutableArray *shops;
 10 @property (nonatomic, weak) HMWaterflowView *waterflowView;
 11 @end
 12 
 13 @implementation HMShopsViewController
 14 
 15 - (NSMutableArray *)shops
 16 {
 17     if (_shops == nil) {
 18         self.shops = [NSMutableArray array];
 19     }
 20     return _shops;
 21 }
 22 
 23 - (void)viewDidLoad
 24 {
 25     [super viewDidLoad];
 26     
 27     // 0.初始化数据
 28     NSArray *newShops = [HMShop objectArrayWithFilename:@"2.plist"];
 29     [self.shops addObjectsFromArray:newShops];
 30     
 31     // 1.瀑布流控件
 32     HMWaterflowView *waterflowView = [[HMWaterflowView alloc] init];
 33     waterflowView.backgroundColor = [UIColor redColor];
 34     // 跟随着父控件的尺寸而自动伸缩
 35     waterflowView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
 36     waterflowView.frame = self.view.bounds;
 37     waterflowView.dataSource = self;
 38     waterflowView.delegate = self;
 39     [self.view addSubview:waterflowView];
 40     self.waterflowView = waterflowView;
 41     
 42     // 2.继承刷新控件
 43 //    [waterflowView addFooterWithCallback:^{
 44 //        NSLog(@"进入上拉加载状态");
 45 //    }];
 46     
 47 //    [waterflowView addHeaderWithCallback:^{
 48 //        NSLog(@"进入下拉加载状态");
 49     //    }];
 50     
 51     [waterflowView addHeaderWithTarget:self action:@selector(loadNewShops)];
 52     [waterflowView addFooterWithTarget:self action:@selector(loadMoreShops)];
 53 }
 54 
 55 - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
 56 {
 57 //    NSLog(@"屏幕旋转完毕");
 58     [self.waterflowView reloadData];
 59 }
 60 
 61 - (void)loadNewShops
 62 {
 63     static dispatch_once_t onceToken;
 64     dispatch_once(&onceToken, ^{
 65         // 加载1.plist
 66         NSArray *newShops = [HMShop objectArrayWithFilename:@"1.plist"];
 67         [self.shops insertObjects:newShops atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newShops.count)]];
 68     });
 69     
 70     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 71         // 刷新瀑布流控件
 72         [self.waterflowView reloadData];
 73         
 74         // 停止刷新
 75         [self.waterflowView headerEndRefreshing];
 76     });
 77 }
 78 
 79 - (void)loadMoreShops
 80 {
 81     static dispatch_once_t onceToken;
 82     dispatch_once(&onceToken, ^{
 83         // 加载3.plist
 84         NSArray *newShops = [HMShop objectArrayWithFilename:@"3.plist"];
 85         [self.shops addObjectsFromArray:newShops];
 86     });
 87     
 88     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 89         
 90         // 刷新瀑布流控件
 91         [self.waterflowView reloadData];
 92         
 93         // 停止刷新
 94         [self.waterflowView footerEndRefreshing];
 95     });
 96 }
 97 
 98 #pragma mark - 数据源方法
 99 - (NSUInteger)numberOfCellsInWaterflowView:(HMWaterflowView *)waterflowView
100 {
101     return self.shops.count;
102 }
103 
104 - (HMWaterflowViewCell *)waterflowView:(HMWaterflowView *)waterflowView cellAtIndex:(NSUInteger)index
105 {
106     HMShopCell *cell = [HMShopCell cellWithWaterflowView:waterflowView];
107     
108     cell.shop = self.shops[index];
109     
110     return cell;
111 }
112 
113 - (NSUInteger)numberOfColumnsInWaterflowView:(HMWaterflowView *)waterflowView
114 {
115     if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
116         // 竖屏
117         return 3;
118     } else {
119         return 5;
120     }
121 }
122 
123 #pragma mark - 代理方法
124 - (CGFloat)waterflowView:(HMWaterflowView *)waterflowView heightAtIndex:(NSUInteger)index
125 {
126     HMShop *shop = self.shops[index];
127     // 根据cell的宽度 和 图片的宽高比 算出 cell的高度
128     return waterflowView.cellWidth * shop.h / shop.w;
129 }
130 @end

知识点分析:1:利用MJEXtension将plist文件转化成模型数组:NSArray *newShops = [HMShop objectArrayWithFilename:@”2.plist”]; [self.shops addObjectsFromArray:newShops];2:向数据源中添加数据:addObjectsFromArray , insertObject atIndexes :NSArray *newShops = [HMShop objectArrayWithFilename:@”1.plist”]; [self.shops insertObjects:newShops atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, newShops.count)]];

2:监听屏幕的旋转:在控制器中实现didRotateFromInterfaceOrientation,可以实现对屏幕旋转的监听,此时设置waterFlow的autoresizingMask属性,设置其宽高随父视图宽高自由伸缩,waterflowView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;在返回列数的代理方法中,根据屏幕的方向,来确定列数

if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {

// 竖屏

return 3;

} else {

return 5;

}

3:MJRefresh:添加上拉刷新,下拉加载更多。两种方法1:block回调的方式 2:addTarget 方式来添加 。停止刷新:

[self.waterflowView headerEndRefreshing];

[self.waterflowView footerEndRefreshing];

4:GCD执行一次函数:

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

// 加载3.plist

NSArray *newShops = [HMShop objectArrayWithFilename:@”3.plist”];

[self.shops addObjectsFromArray:newShops];

});

5:在返回cell高度的方法中:要根据cell的宽度 和 图片的宽高比 算出 cell的高度。

HMShop *shop = self.shops[index];

// 根据cell的宽度 和 图片的宽高比 算出 cell的高度

return waterflowView.cellWidth * shop.h / shop.w;

6:cell的封装

1 #import "HMWaterflowViewCell.h"
2 @class HMWaterflowView, HMShop;
3 
4 @interface HMShopCell : HMWaterflowViewCell
5 + (instancetype)cellWithWaterflowView:(HMWaterflowView *)waterflowView;
6 
7 @property (nonatomic, strong) HMShop *shop;
8 @end
 1 #import "HMShopCell.h"
 2 #import "HMWaterflowView.h"
 3 #import "UIImageView+WebCache.h"
 4 #import "HMShop.h"
 5 
 6 @interface HMShopCell()
 7 @property (weak, nonatomic) UIImageView *imageView;
 8 @property (weak, nonatomic) UILabel *priceLabel;
 9 @end
10 
11 @implementation HMShopCell
12 
13 
14 + (instancetype)cellWithWaterflowView:(HMWaterflowView *)waterflowView
15 {
16     static NSString *ID = @"SHOP";
17     HMShopCell *cell = [waterflowView dequeueReusableCellWithIdentifier:ID];
18     if (cell == nil) {
19         cell = [[HMShopCell alloc] init];
20         cell.identifier = ID;
21     }
22     return cell;
23 }
24 
25 - (id)initWithFrame:(CGRect)frame
26 {
27     self = [super initWithFrame:frame];
28     if (self) {
29         
30         UIImageView *imageView = [[UIImageView alloc] init];
31         [self addSubview:imageView];
32         self.imageView = imageView;
33         
34         UILabel *priceLabel = [[UILabel alloc] init];
35         priceLabel.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3];
36         priceLabel.textAlignment = NSTextAlignmentCenter;
37         priceLabel.textColor = [UIColor whiteColor];
38         [self addSubview:priceLabel];
39         self.priceLabel = priceLabel;
40     }
41     return self;
42 }
43 
44 - (void)setShop:(HMShop *)shop
45 {
46     _shop = shop;
47     
48     self.priceLabel.text = shop.price;
49     [self.imageView sd_setImageWithURL:[NSURL URLWithString:shop.img] placeholderImage:[UIImage imageNamed:@"loading"]];
50 }
51 
52 - (void)layoutSubviews
53 {
54     [super layoutSubviews];
55     
56     self.imageView.frame = self.bounds;
57     
58     CGFloat priceX = 0;
59     CGFloat priceH = 25;
60     CGFloat priceY = self.bounds.size.height - priceH;
61     CGFloat priceW = self.bounds.size.width;
62     self.priceLabel.frame = CGRectMake(priceX, priceY, priceW, priceH);
63 }
64 
65 @end

7:model的封装

1 #import <Foundation/Foundation.h>
2 
3 @interface HMShop : NSObject
4 @property (nonatomic, assign) CGFloat w;
5 @property (nonatomic, assign) CGFloat h;
6 @property (nonatomic, copy) NSString *img;
7 @property (nonatomic, copy) NSString *price;
8 @end
1 #import "HMShop.h"
2 
3 @implementation HMShop
4 
5 @end

 

IOS开发之—初识Block

正文
Block简介
我们可以把Block当做Objective-C的匿名函数。Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观。另外,block的实现具有封闭性(closure),而又能够很容易获取上下文的相关状态信息。
Block的创建
实际上,block使用了与 函数相同的机制:可以像声明函数一样,来声明一个bock变量;可以利用定义一个函数的方法来定义一个block;也可以将block当做一个函数来调用。
 1     // main.m 
 2     #import <Foundation/Foundation.h> 
 3       
 4     int main(int argc, const char * argv[]) { 
 5         @autoreleasepool { 
 6             // Declare the block variable 
 7             double (^distanceFromRateAndTime)(double rate, double time); 
 8       
 9             // Create and assign the block 
10             distanceFromRateAndTime = ^double(double rate, double time) { 
11                 return rate * time; 
12             }; 
13             // Call the block 
14             double dx = distanceFromRateAndTime(35, 1.5); 
15       
16             NSLog(@"A car driving 35 mph will travel " 
17                   @"%.2f miles in 1.5 hours.", dx); 
18         } 
19         return 0; 
20     }

在上面的代码中,利用插入符(^)将distanceFromRateAndTime变量标记为一个block。就像声明函数一样,需要包含 返回值的类型,以及参数的类型,这样编译器才能安全的进行强制类型转换。插入符(^)跟指针(例如 int *aPointer)前面的星号(*)类似——只是在声明的时候需要使用,之后用法跟普通的变量一样。

block的定义本质上跟函数一样——只不过不需要函数名。block以签名字符串开始:^double(double rate, double time)标示返回一个double,以及接收两个同样为double的参数(如果不需要返回值,可以忽略掉)。在签名后面是一个大括弧({}),在这个 括弧里面可以编写任意的语句代码,这跟普通的函数一样。
当把block赋值给distanceFromRateAndTime后,我们就可以像调用函数一样调用这个变量了。
不带参数的Block
如果block不需要任何的参数,那么可以忽略掉参数列表。另外,在定义block的时候,返回值的类型也是可选的,所以这样情况下,block可以简写为^ { … }:
1     double (^randomPercent)(void) = ^ { 
2         return (double)arc4random() / 4294967295; 
3     }; 
4     NSLog(@"Gas tank is %.1f%% full", 
5           randomPercent() * 100);

在上面的代码中,利用内置的arc4random()方法返回一个32位的整型随机数——为了获得0-1之间的一个值,通过除以arc4random()方法能够获取到的*大值(4294967295)。

到现在为止,block看起来可能有点像利用一种复杂的方式来定义一个方法。事实上,block是被设计为闭包的(closure)——这就提供了一种新的、令人兴奋的编程方式。
Block的闭包性(closure)
在block内部,可以像普通函数一样访问数据:局部变量、传递给block的参数,全局变量/函数。并且由于block具有闭包性,所以还能 访问非局部变量(non-local variable)。非局部变量定义在block之外,但是在block内部有它的作用域。例如,getFullCarName可以使用定义在block 前面的make变量:
1     NSString *make = @"Honda"; 
2     NSString *(^getFullCarName)(NSString *) = ^(NSString *model) { 
3         return [make stringByAppendingFormat:@" %@", model]; 
4     }; 
5     NSLog(@"%@", getFullCarName(@"Accord"));    // Honda Accord

非局部变量会以const变量被拷贝并存储到block中,也就是说block对其是只读的。如果尝试在block内部给make变量赋值,会抛出编译器错误。

以const拷贝的方式访问非局部变量,意味着block实际上并不是真正的访问了非局部变量——只不过在block中创建了非局部变量的一个 快照。当定义block时,无论非局部变量的值是什么,都将被冻结,并且block会一直使用这个值,即使在之后的代码中修改了非局部变量的值。下面通过 代码来看看,在创建好block之后,修改make变量的值,会发生什么:
1     NSString *make = @"Honda"; 
2     NSString *(^getFullCarName)(NSString *) = ^(NSString *model) { 
3         return [make stringByAppendingFormat:@" %@", model]; 
4     }; 
5     NSLog(@"%@", getFullCarName(@"Accord"));    // Honda Accord 
6       
7     // Try changing the non-local variable (it won't change the block) 
8     make = @"Porsche"; 
9     NSLog(@"%@", getFullCarName(@"911 Turbo")); // Honda 911 Turbo
block的闭包性为block与上下文交互的时候带来*大的便利性,当block需要额外的数据时,可以避免使用参数——只需要简单的使用非局部变量即可。
修改非局部变量
冻结中的非局部变量是一个常量值,这也是一种默认的安全行为——因为这可以防止在block中的代码对非局部变量做了意外的修改。那么如果我们 希望在block中对非局部变量值进行修改要如何做呢——用__block存储修饰符(storage modifier)来声明非局部变量:
1     __block NSString *make = @"Honda";

这将告诉block对非局部变量做引用处理,在block外部make变量和内部的make变量创建一个直接的链接(direct link)。现在就可以在block外部修改make,然后反应到block内部,反过来,也是一样。

通过引用的方式访问非局部变量
这跟普通函数中的 静态局部变量(static local variable)类似,用__block修饰符声明的变量可以记录着block多次调用的结果。例如下面的代码创建了一个block,在block中对i进行累加。
1 __block int i = 0; 
2 int (^count)(void) = ^ { 
3     i += 1; 
4     return i; 
5 }; 
6 NSLog(@"%d", count());    // 1 
7 NSLog(@"%d", count());    // 2 
8 NSLog(@"%d", count());    // 3

Block作为函数的参数

把block存储在变量中有时候非常有用,比如将其用作函数的参数。这可以解决类似函数指针能解决的问题,不过我们也可以定义内联的block,这样代码更加易读。
例如下面Car interface中声明了一个方法,该方法用来计算汽车的里程数。这里并没有强制要求调用者给该方法传递一个常量速度,相反可以改方法接收一个block——该block根据具体的时间来定义汽车的速度。
 1     // Car.h 
 2     #import <Foundation/Foundation.h> 
 3       
 4     @interface Car : NSObject 
 5       
 6     @property double odometer; 
 7       
 8     - (void)driveForDuration:(double)duration 
 9            withVariableSpeed:(double (^)(double time))speedFunction 
10                        steps:(int)numSteps; 
11       
12     @end
上面代码中block的数据类型是double (^)(double time),也就是说block的调用者需要传递一个double类型的参数,并且该block的返回值为double类型。注意:上面代码中的语法基本 与本文开头介绍的block变量声明相同,只不过没有变量名字。
在函数的实现里面可以通过speedFunction来调用block。下面的示例通过算法计算出汽车行驶的大约距离。其中steps参数是由调用者确定的一个准确值。
 1     // Car.m 
 2     #import "Car.h" 
 3       
 4     @implementation Car 
 5       
 6     @synthesize odometer = _odometer; 
 7       
 8     - (void)driveForDuration:(double)duration 
 9            withVariableSpeed:(double (^)(double time))speedFunction 
10                        steps:(int)numSteps { 
11         double dt = duration / numSteps; 
12         for (int i=1; i<=numSteps; i++) { 
13             _odometer += speedFunction(i*dt) * dt; 
14         } 
15     } 
16       
17     @end

在下面的代码中,有一个main函数,在main函数中block定义在另一个函数的调用过程中。虽然理解其中的语法需要话几秒钟时间,不过这比起另外声明一个函数,再定义withVariableSpeed参数要更加直观。

 1     // main.m 
 2     #import <Foundation/Foundation.h> 
 3     #import "Car.h" 
 4       
 5     int main(int argc, const char * argv[]) { 
 6         @autoreleasepool { 
 7             Car *theCar = [[Car alloc] init]; 
 8       
 9             // Drive for awhile with constant speed of 5.0 m/s 
10             [theCar driveForDuration:10.0 
11                    withVariableSpeed:^(double time) { 
12                                return 5.0; 
13                            } steps:100]; 
14             NSLog(@"The car has now driven %.2f meters", theCar.odometer); 
15       
16             // Start accelerating at a rate of 1.0 m/s^2 
17             [theCar driveForDuration:10.0 
18                    withVariableSpeed:^(double time) { 
19                                return time + 5.0; 
20                            } steps:100]; 
21             NSLog(@"The car has now driven %.2f meters", theCar.odometer); 
22         } 
23         return 0; 
24     }

上面利用一个简单的示例演示了block的通用性。在iOS的SDK中有许多API都利用了block的其它一些功能。NSArray的 sortedArrayUsingComparator:方法可以使用一个block对元素进行排序,而UIView的 animateWithDuration:animations:方法使用了一个block来定义动画的*终状态。此外,block在并发编程中具有强大 的作用。

定义Block类型
由于block数据类型的语法会很快把函数的声明搞得难以阅读,所以经常使用typedef对block的签名(signature)做处理。 例如,下面的代码创建了一个叫做SpeedFunction的新类型,这样我们就可以对withVariableSpeed参数使用一个更加有语义的数据 类型。
 1     // Car.h 
 2     #import <Foundation/Foundation.h> 
 3       
 4     // Define a new type for the block 
 5     typedef double (^SpeedFunction)(double); 
 6       
 7     @interface Car : NSObject 
 8       
 9     @property double odometer; 
10       
11     - (void)driveForDuration:(double)duration 
12            withVariableSpeed:(SpeedFunction)speedFunction 
13                        steps:(int)numSteps; 
14       
15     @end
许多标准的Objective-C框架也使用了这样的技巧,例如NSComparator。
总结
Block不仅提供了C函数同样的功能,而且block看起来更加直观。block可以定义为内联(inline),这样在函数内部调用的时候 就非常方便,由于block具有闭包性(closure),所以block可以很容易获得上下文信息,而又不会对这些数据产生负面影响。

iOS开发中的Assets.xcassets和Assets.car

写在前面
在iOS开发中,*终项目的大小跟项目中的图片关系很大,因为代码的大小是很小的,可以说影响*终项目大小的主要就是项目中的图片资源,所以如何组织项目中的图片资源显得尤为重要。

正文
Assets.xcassets文件
当你创建一个空项目时,会默认帮你生成一个Assets.xcassets文件,当然你也可以自己创建:

%title插图%num
如果没有特殊的需求,一个工程里有一个xcassets文件就可以了,项目中所有图片都可以放在里面,为了组织更有条理更清晰,可以在这里面用文件夹分类,可以按照功能的模块来分类,比如一个模块的功能放在一个文件夹中。

%title插图%num

在这个文件中默认会有一个AppIcon的文件,可以将相对应大小的应用图标直接拖到右边对应大小的地方,就可以了。处理AppIcon这里面还可以放LaunchImage,只要在这个AppIcon这个栏内右键新建即可,还可以针对不同设备新建不同的LaunchImage和AppIcon

%title插图%num

如果只想往项目里加入一张普通的图片,就选择New Image Set,这个Image Set实质就是一个文件夹,里面包括不同分辨率的图片和一个Contents.json文件,内容如下包含着这个图片集中图片文件的基本信息,同AppIcon一样,只要将自己的图片拖到相应的位置即可,然后在项目中使用imageNamed:方法时,使用的名字是这个Image Set的名字,而不是图片真实的名字,这里可以注意的是图片真实的名字虽然无所谓,但*好还是按照一些规律来,*好不要出现中文,而Image Set的名字可以定义一些规则:如用image开头,中间加上模块名,*后加上图片本身的名字,中间用下划线连接,当然这里只是我个人的提议,我们项目中图片就是用这种方式进行命名的。

{
“images” : [
{
“idiom” : “universal”,
“filename” : “sPECIALOFFERIconSurvey1.png”,
“scale” : “1x”
},
{
“idiom” : “universal”,
“filename” : “[email protected]”,
“scale” : “2x”
},
{
“idiom” : “universal”,
“filename” : “[email protected]”,
“scale” : “3x”
}
],
“info” : {
“version” : 1,
“author” : “xcode”
}
}

 

将图片放在xcassets文件中的好处:

组织清晰
不同功用的图片有专门的格式
不同分辨率的图片好管理
工程打包后会对图片进行压缩
这里我要着重说一下第四点,包的大小,如果将图片直接放在工程目录下面,项目打包后图片文件也是散落在包里面,而且不会对图片进行压缩,而如果放在xcassets中,在打包后会将这些图片(除了AppIcon和LaunchImage,这两种图片是直接放在包中的)统一压缩成一个Assets.car的文件,大大减小包的大小,具体是几倍的关系我记不清了,但是相当的可观。

Assets.car文件
说完Assets.xcassets,那么说说由它生成的Assets.car文件,这个文件是一种压缩文件。
我们在开发过程中肯定会遇到一种情况就是把一个ipa的包解压出来看看里面有哪些图片,不管是不是自己的项目,总可能会有这种需求,那如果图片都在Assets.car中该怎么获取呢,直接解压是不行的,这时候就需要用到一个命令行工具叫cartool,这是一个开源软件,可以从github下载,这里给出github地址:https://github.com/steventroughtonsmith/cartool

使用方法是cartool Assets.car outputDirectory

还是给大家上一张图

%title插图%num

先将ipa解压缩,然后显示app包的内容,将Assets.car复制到桌面,然后就可以像上图一样,当然要在桌面上新建一个文件夹,如果你想直接把图片解压到桌面上我也是不介意的!

后记
这篇博客大概就是这些内容,主要就是给大家分享这个叫做cartool的工具还有就是科学的组织项目中的图片,当然要感谢大神写出这样方便的工具。

话说这个月已经过去一半了,然而这是这个月的*篇博客,还需加油,努力学习,努力写博客,分享知识,分享快乐,每月四篇一定要实现。

iOS开发小技巧:如何在xib下给view设置0.5的高度(即1个像素)

引言:在使用xib的时候,使用view画线,但是发现无论怎么样,都无法设置view的高度为0.5,也就是1个像素点。那该如何实现该操作呢?

问题解决过程:
网上有人说当view的高度刚开始设置的是1(2个像素点)的时候,再重新修改是无法改变的,只有重新添加一个view并设置高度为0.5,然而效果并不是很出色,运行的时候还是变成了1。(此方法无效)
有人说网上有库,我没来得及搜索就已经找到解决方案了。
解决方案:
高度设置为1,颜色按UI标注的颜色,然后设置view的alpha为0.5。 运行后,你会惊奇的发现,结果与UI效果是一模一样的。

IOS多线程实现方式

*近突然想起要提高我们开发的效率,而不是自己硬要像老牛那样勤勤恳恳的一步一步的做。

对于Xcode是我们的开发环境,ok,怎样提高我们的效率呢,当然是使我们Xcode的变得更强大了,而Xcode支持插件,这些插件帮助我们的Xcode,使它变得强大。

首先是下载一个Xcode下面的插件包管理器Package Manager,这个可以帮我们管理Xcode大部分常用的插件。我们可以看到很多插件。当然这些插件不是每个都需要用到下载下来安装。自己安装主要有这些:

CComent,类似与C的注释风格/**/快速注释其实xcode自带一大段代码注释快捷键。command+/键。选中需要注释的段落。

ClangFormat,帮助你调整成Clang风格的代码格式。

CocoaPods,名气在外,帮你管理链接需要用到的开源库,简单易用。

FuzzyAutoComplete,个人觉得非常好用,自动提醒补全你将要输入的函数,变量等。

HOStringSense,输入大文本编辑利器,帮你统计文本字数,自动帮你添加一些特殊字符的转移,换行符等。

KSImageNamed,很好,毕竟我们的应用经常需要与图片打交道,管你工程内部的图片资源,当你使用[UIImage ImageNamed:]时会显示工程中的所有图片,供你选择,帮你填充图片名字,不用自己再哈戳戳的跑到Image文件夹下面看看那个图片文件叫什么名字。

Lin,如果你的应用需要支持多国语言,这是一个利器。当你使用NSLocaLiseString时自动显示你的工程中的所有string,供你选择。

OMClorSense,我们的应用经常要跟颜色打交道吧,当你使用NSColor和UIColor时自动显示你输入的颜色,并且可以显示出颜色拾取器,根据你选择的颜色,自动改变你的代码。

SCCodeMiniMap,将你的代码缩小在编辑区的右部,你可以看到你的整个文件下的代码,可以快速跳转到你选择的代码区域,对于一个文件几大千和上万行的代码的话,还是有一定的作用,不过个人觉得还是Xcode自带的函数调转功能好用。这个东西把代码缩小的太小了,你都不知道写的什么,只是知道个大概的位置。

XAlign,帮助你排版代码,使代码更加整洁。

XcodeBoost,帮组你自己更加定制一些功能,如可以在一个代码片段内,将选中的所有相同的字符串高亮等。

等于编写代码而言,比不是所有的代码都要自己下载,自己通常参考下面的一些网站的代码:

http://code4app.com/ Code4App

https://www.cocoacontrols.com/ cocoacontrols

http://github.ibireme.com/github/list/ios/# github所有开源的Code的一个总结

http://www.google.com.hk 哈哈,google对没错就是它,靠谱些。

http://stackoverflow.com/ 牛逼的网站,google出来的问题很多都是这个上面解决的。

https://developer.apple.com/library/ios/navigation/index.html 当然不能忘了,我们的老本行,苹果的开发者文档。
当然我们也需要其他一些独立的应用来帮助我们提高开发效率了。

PhotoShop , 开发人员有时也需要自己处理一些简单的图片,会点总比不会强,当然我们也不会抢了设计师的饭碗。

ImageOption,有时我们需要缩小我们的开发包,就需要将里面的图片进行缩小,该工具可以将图片尽量不变质的缩小。

IFunBox/iTools,我们有时需要查看真机上面的应用程序中的文件。它可以。

Simpholders,如果我们需要查看我们应用在模拟器运行产生的文件的位置时,是不是很麻烦,先在程序中自己打印文件保存的路径,再自己打开文件自己去找,有了这个,一切都不需要了,它可以保存你*近打开的应用,快速跳转到该应用再mac上面的文件夹的地址。

Charles,搞个破解版的,网络调试的利器,因为我们的很多应用都是需要交互的,都会和服务器进行交互,那就必须用到网络,这个工具可以帮你分享真个网络过程,截获你的网络数据进行分析。

DiffMerge,一个轻量级的文件夹比较工具,做开发的那个没有做过code 的merge。

SQLiteManager,一个数据库的查看工具,你的应用十有八九都会再本地进行数据保存,那十有八九会用到数据库来进行保存。

TextMate/TextWranger,搞开发的十有八九需要用到一个文本编辑的工具,查看各种编码的文本。

TestFlight,一个测试的工具,个人还没有怎么使用过。不过貌似用的人还是很多,好像还能进行版本的管理。

briefs,一个快速的原型设计工具,支持IPhone,IPad,安装下来个人没怎么使用过,

http://www.invisionapp.com/ ,在线的原型设计工具。还不错。

http://www.pttrns.com/categories/17-lists ,一个设计风格的展示网站,可以看各种控件的使用风格。

iOS开发60分钟入门

本文面向已有其它语言(如Java,C,PHP,Javascript)编程经验的iOS开发初学者,初衷在于让我的同事一小时内了解如何开始开发iOS App,学习目标包括:

  • 能使用Xcode IDE、模拟器
  • 能修改、调试已有iOS App
  • 能在已有应用内创建新模块
  • 能创建新应用
  • 能发布应用到App Store

本文不包含任何高级的iOS开发知识,已学会iOS开发的同学不要看,看完这篇文章学会了的同学也不用再看了。

不仅是学习一门新语言

有过脚本开发经验的人(如Javascript,PHP,Shell)在刚开始学习iOS开发的时候,会觉得iOS开发的学习曲线比脚本语言要高,是的,这种感觉是对的。因为学iOS开发,不仅是学习一门新语言,它包括:

  • 一门语言:Objective-C
  • 一个框架:Cocoa Touch
  • 一个IDE:Xcode

初学脚本语言通常不会来绘制图形界面、与人交互,iOS如果不做图形界面,像脚本语言一样处理文本操作数据库,就没啥意思了。

所以,过去我写别的新手入门教程,通常都是写《XXX入门15分钟教程》,而iOS就要花数倍的时间来写了。

环境准备

做iOS开发一定要有苹果的软件环境:Mac OS操作系统、Objective-C编译器、设备模拟器等,开发工具倒不一定要用Xcode,只要是个源代码编辑工具就行(vim都行,只是没Xcode那么多功能)。

Mac OS

拥有Mac OS环境*简单的方法是找一台苹果电脑,包括iMac, MacBook Pro, MacBook Air, Mac Mini,但不包括苹果的移动设备(iPod Touch, iPhone, iPad, iPad Mini,它们运行的是iOS系统,不是Mac OS),苹果电脑在出厂的时候就会预装Mac OS,目前*新版本是Mac OS X 10.8,主流的版本还有Mac OS X 10.6、Max OS X 10.7。

如果囊中羞涩,可以借一台,或者上淘宝买个二手的。

黑苹果

提到iOS开发入门,似乎没办法不说黑苹果。所谓黑苹果,就是把Mac OS改造后安装在非苹果的硬件上,这是违反DMCA法案的,黑苹果的更多资料,可以在维基上找到

苹果电脑价格高,国内软件开发者生存压力大,所以黑苹果在国内也有一些真实的存在,国外当然也有啦。

黑苹果基本可以胜任iOS开发,但有一些问题:

  • 安装黑苹果是非法的
  • 个人行为苹果公司一般不会追究,但会遭同行的鄙视
  • 黑苹果超级难装,挑硬件。即使完全相同的型号,相同的批次,也有可能A机器装上了,B机器装不上
  • 黑苹果系统多少都存在一些使用上的问题,像驱动Bug啦、待机恢复蓝屏啦、上网浏览有问题啦
  • 黑苹果不能随意升级,可能升级一次safari就导致整个系统崩溃了

上面这些虽然不会直接影响Xcode写代码、模拟器测试,但写着写着想上网查个东西的时候,safari不能翻页,确实挺影响心情的。所以,钱包允许的前提下,还是搞个苹果电脑省心一些。

Xcode 和 模拟器

Xcode可以在苹果官网免费下载:Xcode下载地址

安装Xcode时会自动安装iOS SDK和模拟器。

这么强大的IDE居然是免费的,还是挺让人开心的。

从改一个现成的应用开始吧

学一门新软件开发技能,能够*时间做出一个可运行的产品非常重要,有助于给自己正面激励,我上大学的时候,有很多次想学一门新语言,往往花了半个月,还沉浸在数据类型和语法字典里,连*个Hello World都没做出来。

这一次,就让我们从改一个现成的应用开始吧。

下载

首先,我们从苹果开发者中心下载一个示例代码回来。我选了ToolBarSearch。

在本文档的末尾,还有一些其它的网址可以下载开源iOS产品或者代码段,但我试了一下,还是Apple Sample Code*容易成功。

下载回来的zip文件*好保存在”下载”或者”文稿”目录里,因为在Mac OS 10.8以前,有些目录(例如/var/private/tmp)在Finder中是看不到的,要通过Finder的“前往 > 前往文件夹”功能才能进入。

打开

有三种方式可以打开一个iOS Project

双击project文件

打开Finder,进入刚刚下载解压的ToolBarSearch目录,找到ToolBarSearch.Xcodeproj文件,双击之,Xcode会自动启动,并打开这个项目

在Xcode里选择Project打开

  • 在Xcode没启动的情况下(如果Xcode已经启动了,就先按Command Q退出),启动Xcode,会弹出“Welcome to Xcode”的欢迎页,点击左下角的“Open Other”按钮,找到ToolBarSearch目录,双击ToolBarSearch目录,或者双击ToolBarSearch.Xcodeproj文件都可以
  • 如果Xcode处于打开状态,可以点击其菜单栏的File -> Open,或者File -> Open Recent,然后再选择要打开的项目

通过命令行打开

在Mac OS 10.8以前,有些目录(例如/var/private/tmp),在Finder和Xcode的File > Open对话框中,点击鼠标是找不到的,这时候就要通过命令行终端来打开了。

打开终端,执行:

  1. cd /ToolBarSearch的父目录/ToolBarSearch
  2. open -a Xcode

open -a是mac os的系统命令,除了iOS项目,别的项目也可以这样打开。

运行刚下载的应用

点击Xcode左上角的Run按钮(或者同时按下Comman和R键),Xcode会编译源码并在模拟器中运行这个应用。

编译成功会在屏幕上淡淡地显示“Build Succeeded”。反之,失败就显示“Build Failed”且不启动模拟器。

修改

在模拟器上看到“Performed search using…”了吧,下面我们改掉它。

  • 在Xcode左上角的Run按钮下方,有一排小按钮,从左到右第三个是一个放大镜图标,鼠标移上去会显示“Show the Search Navigator”,点一下它,打开搜索界面,在它下方出现的Find输入框中输入“performed”
  • 搜索结果只有一条:ToolbarSearchViewController.m,点文件名下方被高亮的“Performed”字串,右侧代码编辑区会自动打开这个文件,并滚动屏幕,使包含“Performed”的这一行出现在编辑区的中间。
  • 修改双引号里的字串,随便改成啥,然后按“Command S”保存。

当然,这些操作,你也可以在终端下通过grep和vim完成。

运行修改后的应用

按Command R运行,看看,是不是看到效果啦?

是的,修改一个应用就这么简单。

Objective-C

Objective-C是苹果应用软件(包括苹果电脑上的Mac OS App和移动设备上的iOS App)的开发语言。它是一种面向对象的编程语言。

苹果公司还提供了一个软件,叫Interface Builder,简称IB,用于可视化的界面制作,就像用Dreamweaver做网页,或者像Visual Basic做桌面软件一样。后来IB就整合进了Xcode,成了Xcode的一部分。这篇文档不讲IB,只讲Objective-C,因为:

  • 基本上,每一本讲iOS开发的书(纸质书、电子书),都有大量的截图一步一步教如何用IB开发iOS应用,而讲Objective-C开发应用的书却没有那么多。
  • IB可以用来直观方便地画界面、设置控件属性、建立代码与控件的联系,但后台的业务逻辑和数据处理仍然要靠Objective-C,可见,不管用不用IB,Objective-C都是绕不过去的。

C的超集

Objective-C扩展了ANSI C,是C的超集,也就是说:

  • 任何C源程序,不经修改,即可通过Objective-C编译器成功编译
  • Objective-C源程序中可以直接使用任何C语言代码

除了面向对象有语法是SmallTalk风格的(下面会讲到),其它非面向对象的语法、数据类型,与C完全相同,所以本文就不再赘述。 来看一个经典的Hello World示例吧:

  1. #import <Foundation/Foundation.h>
  2. int main(int argc, char *argv[]){
  3. @autoreleasepool{
  4. NSLog(@”Hello World!”);
  5. }
  6. return 0;
  7. }

是不是仿佛穿越回了大一学习C语言的时代,看起来和C几乎没有区别,是吧?是的,因为还没用到它的面向对象特性,哈哈!

SmallTalk的消息传递语法风格

Objective-C的面向对象语法源自SmallTalk,消息传递(Message Passing)风格。在源码风格方面,这是它与C Family语言(包括C/C++、Java、PHP)差别*大的地方。

在Java、C++世界,我们调用一个对象的某方法,在Objective-C里,这称作给类型发送一个消息,这可不仅仅是文字游戏,他们的技术细节也是不同的。

在Java里,对象和方法关系非常严格,一个方法必须属于一个类/对象,否则编译是要报错的。而在Objective-C里,类型和消息的关系比较松散,消息处理到运行时(runtime)才会动态决定,给类型发送一个它无法处理的消息,也只会抛出一个异常,而不会挂掉。

[obj undefinedMethod];

在代码里调用没定义的方法(这是Java世界的习惯说法啊,专业的叫法是,给obj对象传递它无法处理的消息),Xcode会警告,但编译能成功,运行的时候会出错。它会输出这样一个错误:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSObject undefinedMethod]: unrecognized selector sent to instance 0x8871710'

类似Java的OOP概念

Objective-C中一些面向对象的概念,也可以在Java中找到类似的实现(只能说是类似,不是完全相同),我的读者基本都是Java和PHP程序员,我会在下文中尽量用Java的概念来类比。

GoogleCode上有人整理了Java和Objective-C的概念、数据类型对应表,参见这里

字符串

Objective-C里有字符串是由双引号包裹,并在引号前加一个@符号,例如:

  1. title = @“Hello”;
  2. if(title == @“hello”) {}

PHP程序员要注意,在这里不能用单引号,即使只有一个字符也不能用。Objective-C与Java、C一样,双引号表示字符串。

函数调用

前文述及,不涉及面向对象时,它和C是完全一样的。以下是几个函数调用的示例:

不带参数

startedBlock();

带参数

  1. NSLog(@“decrypted string: %@”, str);
  2. CGRectMake(0,0,0,0);

传递消息给类/实例方法

不带参数

[obj method];

对应的Java版本

obj.method();

带一个参数:

[counter increase:1];

对应的Java版本

counter.increase(1);

带多个参数

对C Family程序员来说,这是*难接受的,*反人类的:

  1. – (void) setColorToRed: (float)red Green: (float)green Blue:(float)blue {…} //定义方法
  2. [myObj setColorToRed: 1.0 Green: 0.8 Blue: 0.2]; //调用方法

对应的Java版

  1. public void setColorToRedGreenBlue(float red, float green, float blue) {…}
  2. myObj.setColorToRedGreenBlue(1.0, 0.8, 0.2);

消息嵌套

UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];

对应的Java版

UINavigationBar bar = UINavigationBar.alloc().init().autorelease();//Java没有指针,所以星号去掉了

接口和实现

Objective-C的类分为接口定义和实现两个部分。接口定义(Interface)放在头文件中,文件扩展名是.h,实现(implementation)放在实现文件中,文件扩展名是.m(也有.mm的扩展名,表示Objective-C和C++混编的代码)。

接口定义也可以写在.m文件中,但*好不要这么干

需要注意的是,与Objective-C的interface概念*接近的是C和C++里的头文件,它与implementation是成双成对出现的,作用是声明类的成员变量和方法。它与Java的interface概念完全不同:

  • Objective-C里,interface有且只有一个实现,Java的interface可以有0-N个实现
  • Objective-C里,interface可以定义成员属性,Java里不可以

在Objective-C里,和Java的Interface概念相似的是Protocol,下文会讲到。

请看示例:

Interface

  1. @interface MyClass {
  2. int memberVar1;
  3. id memberVar2;
  4. }
  5. -(return_type) instance_method1;
  6. -(return_type) instance_method2: (int) p1;
  7. -(return_type) instance_method3: (int) p1 andPar: (int) p2;
  8. @end

Implementation

  1. @implementation MyClass {
  2. int memberVar3;
  3. }
  4. (return_type) instance_method1 {
  5. ….
  6. }
  7. -(return_type) instance_method2: (int) p1 {
  8. ….
  9. }
  10. -(return_type) instance_method3: (int) p1 andPar: (int) p2 {
  11. ….
  12. }
  13. @end

接口和实现以@interface、@implementation开头,都以@end结束。“@”符号在Objective-C中是个很神奇的符号。

冒号也是方法名的一部分,method和method:是两个不同的方法名,不是overload,第二个带参数。

上述代码对应的Java版:

  1. public class MyClass {
  2. protected int memberVar1;
  3. protected pointer memberVar2;
  4. private int memberVar3;
  5. public (return_type) instance_method1() {
  6. ….
  7. }
  8. public (return_type) instance_method2(int p1) {
  9. ….
  10. }
  11. public (return_type) instance_method3andPar(int p1, int p2) {
  12. ….
  13. }
  14. }

私有方法和公开方法

写在.h头文件里的方法都是公开的,Objective-C里没有私有方法的概念(没有你说个蛋啊,哈哈哈哈)。

官方并没有提到Objective-C怎么实现私有方法,我查阅了stackoverflow,统一的答案是,要实现私有方法的效果只能借助Category,不过,根据我的测试,即使采用了Category,也不能阻止外部的代码调用这个“私有方法”,只是Xcode不支持“私有方法”的自动完成,并会有警告提示,运行的时候,还是会成功的。各位看官知道有这么回事就可以了,这里不深讲。

变量和属性

类方法和实例方法

类方法

类方法就是Java、PHP里的Static Method,不用实例化就能调。类方法有一个加号前缀。 示例:

类定义

  1. @interface MyClass
  2. +(void) sayHello;
  3. @end
  4. @implementation MyClass
  5. +(void) sayHello {
  6. NSLog(@“Hello, World”);
  7. }
  8. @end

使用

[MyClass sayHello];
实例方法

实例方法就是Java、PHP里的普通方法,必须实例化才能调。实例方法有一个减号前缀。 示例:

类定义

  1. @interface MyClass : NSObject
  2. -(void) sayHello;
  3. @end
  4. @implementation MyClass
  5. -(void) sayHello {
  6. NSLog(@“Hello, World”);
  7. }
  8. @end

使用

  1. mycls = [MyClass new];
  2. [mycls sayHello];

Selector

selector就是一个方法指针,类似PHP里的动态方法名:

  1. <?php
  2. class Hello {
  3. public function sayHello() {}
  4. public function test() {
  5. $fun_name = “sayHello”;
  6. $this->$fun_name();
  7. }
  8. }

在Objective-C里,selector主要用来做两类事情:

绑定控件触发的动作
  1. @implementation DemoViewController
  2. – (void)downButtonPressed:(id)sender {//响应“按钮被按下事件”的方法
  3. UIButton *button = (UIButton*)sender;
  4. [button setSelected:YES];
  5. }
  6. – (void)drawAnButton {
  7. UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
  8. btn.frame = _frame;
  9. btn.tag = 1;
  10. btn.backgroundColor = [UIColor clearColor];
  11. [btn addTarget: self
  12. action: @selector(downButtonPressed:)
  13. forControlEvents: UIControlEventTouchUpInside];//当这个按钮被按下时,触发downButtonPressed:方法
  14. }
  15. @end

延时异步执行

  1. @implementation ETHotDealViewController
  2. – (void)viewDidLoad {
  3. //获取数据源
  4. HotDealDataSource *ds = [[HotDealDataSource alloc]init];
  5. [ds reload];
  6. _items = ds.items;
  7. [self performSelector: @selector(refreshTable)
  8. withObject: self
  9. afterDelay: 0.5];//延迟0.5秒调用refreshTable方法
  10. }
  11. -(void)refreshTable
  12. {
  13. [self.tableView reloadData];
  14. }
  15. @end

这个例子中,获取数据源是通过ASIHTTP组件异步调用服务端HTTP接口,refreshTable要用到数据源返回回来的数据,如果不延迟0.5秒,就会立刻执行,执行的时候数据还在路上呢,页面就要变空白了。

继承

继承是写在Interface定义里面的。语法为:子类名在左,父类名在右,中间用冒号分隔。 示例:

  1. @interface MyClass : NSObject
  2. @end

对应的Java版本是:

  1. public class MyClass extends NSObject {
  2. }

协议(Protocol)

就是Java、PHP里的Interface。

协议的定义

协议的定义用@protocol关键字:

  1. @protocol Printable
  2. -(void)print:(NSString)str;
  3. @end

对应的Java版本是:

  1. publilc interface Printable {
  2. public void print(String str);
  3. }
协议的继承

协议本身也可以继承别的协议:

  1. @protocol Printable <NSObject>
  2. -(void)print:(NSString)str;
  3. @end

对应的Java版本:

  1. public interface Printable extends NSObject {
  2. public void print (String str);
  3. }
可选方法

协议可以包含可选方法,顾名思义,可选方法可以不被类实现:

  1. @protocol Printable
  2. @optional
  3. -(void)print:(NSString)str;
  4. @end

加了@optional关键字,一个类在implements这个协议时,便可以不实现print:方法。

Java里没有类似的实现,除了Collection里会有一些方法带有optional的注释,但Collection是个特例。

协议的实现

一个类实现某些协议是写在Interface定义里面的。语法为:协议名用尖括号包裹,多个协议名用逗号隔开,协议写在父类的右边(如果没有父类就直接写在子类右边)。

示例:

  1. @interface class MyClass : NSObject <Printable, Drawable>
  2. @end

Printable, Drawablw就是两个协议。

对应的Java版本是:

  1. public class MyClass extends NSObject implements Printable, Drawable {
  2. }

分类(Category)

分类可以给一个已经存在的类增加方法,而不用去改它的源码。Java和PHP中都没有类似的特性。

比如说,NSObject是一个Objective-C内置的系统类,我们想给它增加toJson方法,就像这样:

头文件:NSObject+Json.h

  1. @interface NSObject (Json)
  2. -(NSString)toJson;
  3. @end

实现文件:NSObject+Json.m

  1. @implementation NSObject (Json)
  2. -(NSString)toJson {
  3. //…
  4. }
  5. @end

使用的时候,只要包含NSObject+Json.h,实例化NSObject类,就可以使用toJson方法了:

  1. import “NSObject+Json.h”
  2. @implatementation XYZController
  3. -(void)test {
  4. NSObject *obj = [[NSObject alloc]init];
  5. NSString *str = [obj toJson];
  6. }
  7. @end

当然了,NSObject本来的那些方法依然还是可以用的,什么都没变,只是多了个toJson方法。看起来是不是和继承没太多差别呢(除了使用的时候实例化的是NSObject,而不是JsonObject)?再看一个继承实现不了的例子:

头文件:NSObject+Json+XML.h

  1. @interface NSObject (Json)
  2. -(NSString)toJson;
  3. @end
  4. @interface NSObject (XML)
  5. -(NSString)toXML;
  6. @end

实现文件:NSObject+Json+XML.m

  1. @implementation NSObject (Json)
  2. -(NSString)toJson {
  3. //…
  4. }
  5. @end
  6. @implementation NSObject (XML)
  7. -(NSString)toXML {
  8. //…
  9. }
  10. @end

使用:

  1. import “NSObject+Json+XML.h”
  2. @implatementation XYZController
  3. -(void)test {
  4. NSObject *obj = [[NSObject alloc]init];
  5. NSString *json = [obj toJson];
  6. NSString *xml = [obj toXML];
  7. }
  8. @end

Cocoa Touch

Cocoa是Mac OS App的开发框架,Cocoa Touch是iOS开发用的框架,Cocoa Touch和Cocoa大部分是一样的,只是Cocoa Touch多了一些移动设备特有的东西,如:触摸屏、加速度传感器、GPS定位。Cocoa中多任务、多窗口的特性,在Cocoa Touch中也是没有的(或者跟Cocoa不完全一样的)。

就像学了Java语言还要再学一些Spring、Hibernate、Struts(或者其它类似的Java类库)才能开始做J2EE应用一样,学过Objective-C语言之后,也要再学习Cocoa Touch框架才能顺利地开发iOS应用。

*常用设计模式之Delegate

Cocoa Touch大量使用Delegate(委派)设计模式。

常用控件:按钮、文本块、图片、输入框

TableView

WebView

导航条

Xcode

运行

快捷键:Comman R

搜索

搜索文本

搜索文件

新建文件/目录

推荐在Finder中新建好的再添加进来

断点

模拟器和真机测试

模拟器测试

在Xcode中打开你的项目,在Xcode顶部工具栏的Stop按钮(Run按钮右边那个黑色正方形按钮)右边,有个下拉菜单,显示着 “ToolBarSearch > iPhone 5.0 Simulator” (即 你的应用英文名 > 当前选中的调试 ),点击这个下拉菜单,选中iPhone 5.0 Simulator(这里的5.0是指iOS版本,不是iPhone5的意思,如果你的项目是iPad应用,请选iPad 5.0 Simulator),再按“Run”按钮,Xcode就会自动把当前正在编辑开发的应用编译并安装到模拟器上。

在模拟器上操作时,如果执行过程中遇到了你在Xcode里设置的断点,模拟器会暂停运行,并将当前活动窗口切换回Xcode,供你调试。

在Xcode里增加或者取消了断点,不需要重新编译和安装应用即可生效。

切换被模拟的设备

模拟器的“硬件”菜单,可以选择想要模拟什么设备,有iPad、iPhone可选。

  • Retina:表示视网膜屏,iPhone(Retina)代表iPhone4,iPhone4S
  • 4-Inch:表示4英寸的iPhone,iPhone(Retina 4-Inch)就是iPhone 5

切换模拟的iOS版本

在模拟器的“版本”菜单,可以选择要模拟什么版本的iOS。设备和版本是彼此独立的,iPhone 4S可以有5.0,5.1,6.1几种iOS版本,当然了,iPhone 5不可能有4.3的iOS版本。

触摸屏

用鼠标点击(不区分左右键)模拟器上的iPhone、iPad屏幕,就是在模拟用手指触摸iPhone,iPad的屏幕,可以实现一些触摸效果比如:

  • 鼠标单击 等于 手指轻触
  • 鼠标长按 等于 手指长按(例如你可以在模拟器上长按应用icon调出删除应用的确认框)
  • 鼠标按住拖动 等于 手指拖动
  • 双击和单击模拟器的Home键也等于双击和单击真机的Home键
多指手势

多指手势比较复杂,在白苹果笔记本上可以模拟简单的双指手势,白苹果的触控板天然支持多指触摸,但要定位到模拟器的区域再响应多指手势就需要借助一些额外的键啦:

  • 按住Option键,再用两个手指去操作触摸板,可模拟双指拖动、旋转
  • 按住Option+Shift,可模拟双指合拢

输入法和键盘

输入中文

手机上特有的输入法(比如九宫格输入法)不能模拟。模拟器默认的iOS软键盘只有英文输入,在测试应用的时候,我们要用到中文,有两个办法:

  • 使用剪贴板,在Mac OS里复制,再到模拟器运行的应用中的输入框上长按鼠标(模拟手指长按)3秒以上,等弹出“粘贴”的时候选择之,即可。
  • 在模拟器里,按Home键,找到Setting那个App icon(不是Mac OS顶部的模拟器菜单啊,那里没有Setting的),打开被模拟iOS设备的设置,依次点击”General – Keyboard – International Keyboards – Add New Keyboard…”,加个中文键盘,以后就可以使用被模拟iOS设备软件盘输入中文了,跟在iPhone/iPad真机上一样。

使用Mac电脑的键盘

如果要输入大量文本,使用模拟器里的软键盘效率太低,这时候可以使用物理键盘,方法是:在Mac OS顶部的模拟器菜单栏,点击”硬件”菜单,勾选下拉菜单中的“模拟硬件键盘”。以后再用模拟器运行iOS应用时,点击iOS应用中的输入框,软键盘就不弹出来了,可直接使用Mac电脑的物理键盘输入。

注意

  • 模拟器中的iOS接管了物理键盘输入,所以,调用的是模拟器iOS的输入法,不是你的Mac电脑的输入法。打个比方,你的Mac OS装的是搜狗五笔,模拟器中iOS加了个拼音输入法(Add New Keyboard),那么,在iOS应用中输入中文会调用拼音输入法。
  • 要切换模拟器中iOS的中英文输入法,也只能按iOS设备软键盘上的小地球图标,按Mac电脑上的Command+空格键是不行的。

地理位置

但Mac电脑没有定位用的硬件(GPS)和软件基础,因此模拟器不能自动获得当前的地理位置,不能用模拟器测试定位功能。(注意,虽然WiFi也可以独立定位——iPad WiFi版没有GPS也可以定位,但Mac电脑的WiFi不具备定位相关的软件)

要在模拟器里测试依赖地理位置的功能(如”我附近的xx”),可以手工指定一个经纬度给模拟器,方法:在Mac电脑顶部的模拟器菜单,点击”调试 – 位置 – 自定位置”,会弹出一个对话框,在弹出的框内填入经纬度即可。

如何获得经纬度? 上谷歌地图(ditu.google.cn),在地图上找到你想要的位置(比如你想知道杭州大厦的位置,就在通过搜索框找到杭州大厦),点击右键,选择“这儿是什么”,搜索框中就会出现这个位置的经纬度了,前面是纬度,后面是经度。咱们天朝的版图,都是北纬和东经。

摄像头

Mac电脑有摄像头,但Mac OS没有设计API给iOS模拟器调用,所以,不能用模拟器测试对焦闪光灯等功能。

要在模拟器上测试依赖照片的功能,可以在代码里做一个workaround,即当代码检测到摄像头不可用时,弹出一个照片选择器,让测试人员从相册里选择一幅照片,来进行后续的操作(如照片美化、人脸识别、条码扫描)。

真机测试

模拟器能验证你开发的iOS应用的大部分功能,但有些Mac设备上不具备的硬件,模拟器是不能模拟的。前文提到了一个绕过这些限制的办法,但获取当前位置、拍照、加速度感应这些是模拟不了的,一款应用发布给消费者之前,必须要在真实设备上验证过。

将未提交App Store审核通过的应用安装到iOS设备上测试,有三种办法:

  • 加入苹果的Developer Program,成为付费会员,有了这个付费会员资格,就可以直接在Xcode中点击”Run”将刚刚改过的代码编译打包安装到开发测试用的iOS设备上。在iOS真机上操作被测试的程序能激活Xcode中设置的断点。
  • 越狱iOS设备。将iPhone和iPad越狱后,可以通过SSH直接上传Xcode编译好的ipa包(一个iOS App本质上就是一个ipa包)。
  • 越狱的iOS设备,配合破解过的Xcode,甚至可以实现和付费开发者计划一样的功能:在Xcode上点击”Run”,就自动编译安装到iOS设备上去运行了
  • 企业部署方案。就像阿里巴巴的轩辕剑一样,用iPhone/iPad访问这个网址,点击里面的轩辕剑链接就可以安装轩辕剑这个应用了。

破解Xcode是违法行为(越狱是合法的),而且挑版本挑得厉害,不是所有Xcode版本都能破解,也不是所有Xcode的破解版都能和越狱的iOS配合好。越狱+SSH上传跟企业部署一样效率低(部署效率低,无法激活Xcode中的断点),只能用于QA验收,不适合开发自测。综上所述,*适合开发实时测试的就是*个正规途径了。下面重点讲这个:

拥有一个开发者账号

苹果的Developer Program分为个人开发者和公司开发者,分别是每年99美元和每年299美元,分别可以注册100台和500台苹果测试设备。这个台数限制在一个付费年度内不会清空,比如说,2013年4月1日付费成功的,付费会员资格在2014年3月31日之前有效,这期间,注册一台就少一个名额,哪怕这个设备注册进来用了之后一分钟马上又删掉了,减少的这个名额也不会回来。

在交钱之前,*好问一下,周围的同事,有没有已经交了钱的。如果有,你只需要注册一个免费的Apple ID(就是你在App Store安装软件用的Apple ID),请他发个邀请邮件给你,把你的Apple ID加入他的团队就可以了,苹果会认为你们两个人是一个团队的,你们分别用自己的账号,共享100台设备的限额,这是合法的。

安装证书和私钥

证书

不想看下面各种点击各种页面跳转的直接用浏览器访问证书管理,你要登录你就用Apple ID登录(前提是交过钱,或者找交了钱的人把你加入团队了)。

不嫌烦,或者想知道下次没我这个文档的时候怎么进证书管理吗?按这个步骤操作:

  • 进入 苹果开发者中心
  • 点击iOS Dev Center
  • 点蓝色“Login”按钮,用你的Apple ID登录,登录成功会跳到 开发者首页
  • 点击右上角的iOS Provisioning Portal(别找了,直接Command F搜索多好)
  • 点左侧菜单栏里的Certificates

页面上有一个“Your Certificate”区域,下方有个Download圆角按钮,这是你的个人证书,下载下来。再下面一行,有一句“If you do not have the WWDR intermediate certificate installed, click here to download now”,这个是苹果的公共证书,也下下来。

双击下载回来的证书,装证书时,会提示你输入密码,这是【钥匙串访问工具】在问你要你的Mac OS账号开机密码(相当于linux里面的sudo),不是Apple ID的密码,不要搞错了。

安装私钥

如果你是和其它同事公用的账号,让他给你一个私钥即可,就是一个扩展名为p12的文件,双击之,钥匙串访问会自动出来,需要你输入一个密码,这个密码问给你p12文件的人要,不是你的Mac OS系统开机密码,也不是你的Apple ID密码。

将设备注册到Provisioning Portal

  • 打开Xcode,从Xcode的Window菜单中找到Organizer,打开之(Shift Command 2)。
  • 把iOS设备连上电脑,Organizer会自动识别出你的设备,并显示在左侧边栏。
  • 在Organizer左侧边栏找到你的设备,右键,点击“Add Device to Provisioning Portal”,然后等Organizer提示你操作成功即可。(选中设备后,右边设备详情区域会显示一个按钮“Use for Development”,点它也可以)。

到iOS真机上运行测试版程序

回到Xcode主界面,在Stop按钮(Run按钮右边那个黑色正方形按钮)右边,有个下拉菜单,显示着 “ToolBarSearch > iPhone 5.0 Simulator” (即 你的应用英文名 > 当前选中的调试 ),点击这个下拉菜单,选中你的真机设备名,再按“Run”按钮,Xcode就会自动把当前正在编辑开发的应用编译并安装到真机上测试啦!

发布到App Store

打IPA包

IPA包本质上是一个ZIP压缩包,只不过它有着特殊的目录结构,扩展名是ipa,制作方法如下:

  • 在Xcode中Build项目,快捷键Command B
  • 在左侧项目导航器中,展开Products文件夹,找到你要打包的应用,你的应用名.app,右键,选择show in finder
  • 到Finder中Copy这个.app目录(选中,按Command C),复制到一个你新建的名为Payload(区分大小写)的文件夹中
  • 找到你的应用Logo,即一个512 * 512像素的PNG文件,copy到与Payload一起(与Payload并列,不要放进Payload了),并重命名为iTunesArtwork(区分大小写,没有扩展名)
  • 将Payload目录、ItunesArtwork文件打成一个zip包,并更改扩展名为ipa
  • 双击这个ipa文件,会用iTunes打开,如果打开成功,且在iTunes里有应用Logo显示,就成功了

批量自动打包

除App Store外,还有许多其它的iOS应用市场(如91助手,同步推等等),如果一个应用需要发布到很多个应用市场,且他们的代码略有不同(比如说,统计代码不同),按上述方法手工修改源码再打包,再还原,比较容易出错。好消息是,Xcode是有命令行的,我们可以写一个shell脚本,先用se自动修改源码,再调用Xcode的命令行来编译以得到your——app.app目录,*后调用zip、mv等命令把上一个章节讲的ipa打包动作自动执行。

阅读应用代码

从头新建一个应用:Hello World

其它

代码里的控件尺寸

iOS App里的控件尺寸和字体大小都是指Point,Retina设备(iPhone 4,4S,5;the new Pad)和非Retina设备(iPhone 3GS,iPad,iPad 2)的Point数是一样的,尽管iPhone 4的分辨率是3GS的2倍。比如说,10point在Retina设备里是20 pixel,在非Retina设备(iPhone 3G)上则是10 pixel。

项目成员间交流时,应使用Point,不要使用pixel。

SVN操作含有@符号的文件

iOS应用中经常出现[email protected]这样的文件名,它们是给retina设备用的高分辨率大图,用svn命令行操作它们的时候会被@符号干扰,解决方案是在svn命令末尾加上一个@符号,如:

  1. svn del icon@2x.png@
  2. svn info Default@2x.png@

如果一次移动了几十个png文件再svn commit的,可以用shell批处理:

svn status | awk '($1=="!"){print $2}' | grep -v @ | xargs svn del

上面这个命令是将文件名不包含@符号的,且已经不在硬盘上的文件从svn version controll中删掉

for file in `svn status | awk '($1=="!"){print $2}' `; do svn del $file"@"; done     

上面这个命令是将文件名包含@符号的,且已经不在硬盘上的文件从svn version controll中删掉

svn add同上, 如法炮制即可.

Xcode中的代码结构与操作系统上的文件系统并不一致

推荐在Finder里建好目录再到Xcode的Project Navigator中点击“Add Files to”添加到项目中

iPhone 5适配

iPhone 5与之前的iPhone不一样,采用了4寸Retina屏,所以它的Point数变成了320 * 568 points

开源代码

  • Apple官方的Sample Code
  • 维基百科上的开源iOS App
  • iOS Opensource –Domain Parking了,以前可以下载Twitter和Wordpress客户端的
  • code 4 app
  • UI 4 app, code4app的姐妹站

Objective-C教程

  • Apple官方教程
  • Cocoa Dev Center
  • 维基上的Objective-C语言简介 –中文,十分钟可读完,推荐

App Store 审核必备

App Store 审核规则中文版
简介
App 正在改变世界,丰富人们的生活,并为像您一样的开发者提供前所未有的创新机会。因此,App Store 已成长为一个激动人心且充满活力的生态系统,正为数百万的开发者和超过十亿的用户提供服务。不管是开发新手,还是由经验丰富的程序员所组成的大型团队,我们都非常欢迎您为 App Store 创建 app,并希望能够帮助您了解我们的准则,以确保您的 app 能够快速通过审核流程。

App Store 的指导原则非常简单:我们希望为用户获取 app 时提供更安全可靠的体验,并为所有开发者提供借助 app 获得成功的契机。在后续页面中,您会发现这些准则已被清晰地划分为五个部分:安全、性能、业务、设计及法律。另外,请将以下几点谨记在心:

很多儿童会从我们这里大量下载各种 app。尽管家长控制功能能为儿童提供有效保护,但您也必须做好自己份内的工作。因此,您要知道,我们时刻都在关注这些儿童。
App Store 是向全球数亿人分享 app 的好方法。如果您开发 app 只是为了分发给亲朋好友,那么 App Store 并不是*适合的途径。这时可考虑使用 Xcode 在设备上安装您的 app,或使用 Apple Developer Program 会员资格中的 Ad Hoc 分发。如果您刚开始开发 app,请进一步了解 Apple Developer Program。
在 App Store 上发布的所有观点,我们都非常支持 — 只要这些 app 尊重用户的不同意见,并能带来良好的 app 体验。如果我们认为 app 的任何内容或行为超出了可接受的范围,我们将拒*该 app。您可能会问,这个可接受的范围是什么?套用*高法院大法官的一句话:“当我看到的时候,我就知道了”。而且,我们相信,当您超出这个范围时,您自己也会意识到。
如果您试图欺骗系统 (例如,试图在审核流程中弄虚作假,窃取用户数据,抄袭其他开发者的作品,或者操纵评级),我们会从商店中移除您的 app,并将您从开发者帐户中除名。
您要确保 app 中所含内容全部符合这些准则的要求,包括广告网络、分析服务和第三方 SDK 等;因此,在审核和选择这些内容时务必要慎重。
我们希望这些准则能帮助您顺利通过 App Review 流程,并使批准和拒*标准在整体上更加一致。本文是一个动态文稿;如果新的 app 引发了新的问题,我们可能会随时制定新的规则。也许,您的 app 就将促成新的规则。我们同样热爱 app 开发,并且尊重您所做的一切。我们正竭尽全力为您营造世界上*优秀的平台,既能让您展示才华,还能让您获得回报。

,

提交之前
为了帮助您尽可能顺利地通过 app 审批,请查看下方列出的常见错误行为,这些行为可能会导致审核流程延误或导致 app 被拒。这些内容不能代替准则或保证 app 获批,但确保核对这个列表中的每一项会是一个良好的开始。如果您的 app 不再能按预期方式工作,或者您不再积*地对其提供支持,那么这个 app 将从 App Store 中移除。进一步了解 App Store 所做的改善。

请确保:

测试 app 是否会发生崩溃、是否存在错误
确保所有 app 信息及元数据完整且正确
更新您的联系信息,以便 App Review 部门在需要时与您取得联系
提供有效的演示帐户和登录信息,以及审核 app 时所需的任何其他硬件或资源 (例如,登录凭证或示例二维码)
启用后台服务,以使其在审核期间处于活动和可用状态
在 App Review 备注中附上与非明显功能及 App 内购买项目相关的详细说明,包括支持文稿 (如适用)。如果由于地区锁定或其他限制而导致我们无法访问 app 的部分内容,请提供有关功能的视频链接
检查 app 是否遵循了其他文稿中的相关指南,如:
开发指南

App 编程指南 (英文)
App 扩展编程指南 (英文)
iOS 数据存储指南 (英文)
macOS 文件系统文档 (英文)
Safari 浏览器扩展开发指南 (英文)
App Store Connect 帮助
设计指南

Human Interface Guidelines (英文)
品牌和营销指南

营销资源和识别标志指南
Apple Pay 识别标志指南 (英文)
“添加到 Apple 钱包” 指南 (英文)
Apple 商标及版权使用准则 (英文)
,

1. 安全
当用户通过 App Store 安装 app 时,他们希望获得安全的体验:app 不含令人不快或具有攻击性的内容,不会损坏用户的设备,不会在使用中造成人身伤害。我们在下方列出了主要的安全隐患。如果您想恐吓或攻击他人,则您的 app 不适合出现在 App Store 中。

1.1 令人反感的内容
App 不应包含具有攻击性、不顾及他人感受、令人不安、惹人厌恶或低俗不堪的内容。此类内容的示例有:

1.1.1 诽谤、歧视或恶意的内容,包括有关宗教、种族、性取向、性别、国籍、种族起源或其他目标群体的引用或评论,特别是当 app 很可能对特定的个人或团体进行羞辱、恐吓、或造成伤害时。通常情况下,专业政治讽刺和政治幽默作家不受此要求限制。
1.1.2 人类或动物遭到杀害、残害、酷刑、虐待的写实描绘,或者鼓励暴力的内容。在游戏中,“敌人”不能单单针对特定种族、文化、真实存在的政府或企业,或是任何其他真实存在的实体。
1.1.3 鼓励非法使用或不负责任地使用武器和危险物品的描述,或者促进军火购买的描述。
1.1.4 过于色情的内容 (韦氏词典对“色情”一词的定义是:对性器官或性活动的露骨描述或展示,目的在于刺激性快感,而非带来美学价值或触发情感)。
1.1.5 具有煽动性的宗教评论,或者对宗教文本进行错误或误导性的引用。
1.1.6 虚假信息和功能,其中包括不准确的设备数据或用于恶作剧/开玩笑的功能,如虚假的位置跟踪器。即使指明 app“仅供娱乐”,也不能违背这一准则。支持匿名或恶作剧电话或短信/彩信的 app 会被拒*。
1.1.7 App Store 评论:
App Store 客户评论是 app 体验中不可或缺的一部分;因此,在回复客户的评论时,您应当对他们保持尊重。另外,您的回复应直接回应客户评论的主题,请勿在回复中包含个人信息、垃圾信息或营销广告。
利用我们提供的 API 提示用户评价您的 app:通过这项便利功能,客户无需离开 app,就可直接在 App Store 中留下评分和评论;不允许使用预定的评论提示。
1.2 用户生成的内容
对于包含用户生成内容的 App,有特定的难题需要解决,比如知识产权侵权、匿名欺凌等。为了避免滥用,包含用户生成内容或社交网络服务的 app 必须满足以下条件:

采用相应的方法来过滤令人反感的内容,以免这些内容在 app 中发布
制定一个机制,以举报攻击性内容并在出现问题时及时作出回应
若用户发布攻击性内容,可以取消其使用服务的资格
公布联系信息,以便用户与您联系
如果 app 中所含的用户生成内容或服务*终主要用于色情内容、客观化现实生活中的某人 (如“性感与否”投票)、进行人身威胁或欺凌,则这些 app 不适合出现在 App Store 中,它们可能会在未经通知的情况下被移除。如果 app 中所含的用户生成内容来自于基于 web 的服务,则可显示意外产生的“NSFW (公众场所不宜)”内容,前提是这些内容是默认隐藏的,只有当用户通过您的网站将其打开时才会显示。

1.3 儿童类别
“儿童类别”可帮助用户轻松找到专为儿童设计的 app。如果您希望参与“儿童类别”,则应该致力于为年纪较小的用户量身打造卓越的使用体验。这些 app 不得提供 app 外链接、购买机会或其他会对儿童造成干扰的内容,除非其保留在受家长监控的指定区域中。请谨记,一旦客户认为您的 app 能够满足“儿童类别”要求,您的 app 就需要一直满足后续更新中的相应准则;即使您决定取消选择此类别,也是如此。进一步了解家长监控。

“儿童类别”中的 app 不得展示行为广告 (例如,广告商不得根据用户在 app 中的活动投放广告),而且所有内容相关广告都必须适合儿童观看。您还应特别留意世界各地与在线收集儿童数据相关的隐私法。请务必查阅这些准则的“隐私”部分,以了解更多信息。

1.4 人身伤害
如果 app 的行为方式可能会造成人身伤害,我们可能会拒*该 app。例如:

1.4.1 如果医疗 app 可能会提供错误的数据或信息,或用于诊断或治疗病患,则这些 app 可能会面临更加严格的审核。
App 必须清楚地披露相关数据和方法,用于佐证声明的健康测量准确度,如果准确度或方法得不到验证,我们会拒*该 app。例如,如果 app 声称仅通过设备上的传感器就能照 X 光、测血压、测体温、测血糖浓度或测血氧含量,则这个 app 会被拒*。
App 应当提醒用户,除了使用该 app,还应咨询医生的意见,然后才能做出医疗决定。
如果您的医疗 app 已经获得监管部门的批准,请随 app 提交相关文稿的链接。
1.4.2 药物剂量计算器必须来自药品生产企业、医院、大学、健康保险公司、药店或经过 FDA 或其相应国际部门的批准的其他实体。由于可能会对病患造成伤害,我们需要确保 app 将在长时间内获得支持,并保持更新。
1.4.3 App Store 中不允许分发任何鼓励食用烟草产品、使用违禁药物或摄入过量酒精的 app。鼓励未成年人摄入任何上述物品的 app 都会被拒*。为大麻、烟草或管制物品的销售提供便利 (经授权的药店除外) 同样不被允许。
1.4.4 App 只能显示由相关执法部门公布的酒后驾车检查点,不得鼓励酒后驾车和包括超速在内的其他鲁莽行为。
1.4.5 App 不得促使客户以违背 Apple 硬件安全文稿的方式,或以可能会造成设备或人身伤害的方式来使用他们的设备。例如,app 不得鼓励在充电期间将设备置于床垫或枕头下,或对固态硬盘进行过多的写入循环操作。请查阅设备文稿。
1.5 开发者信息
用户需要知道如何就疑问和支持问题与您取得联系。确保您的 app 及其支持 URL 中包含能轻松联系到您的联系信息;对于可能会在课堂中使用的 app 而言,这一点尤为重要。如果未能提供准确的*新联系信息,不但会让客户有不好的感受,可能还会违反某些国家/地区的法律。另外,请确保在钱包凭证中包含发卡机构的有效联系方式,以及分配给凭证的品牌或商标所有者的专用证书。

1.6 数据安全
App 应实施适当的安全举措,确保按照“Apple Developer Program 许可协议”和这些准则 (更多信息见“准则 5.1”) 妥善处理收集到的用户信息,防止对这些信息进行未经授权使用、披露或者被第三方访问。

,

2. 性能
2.1 App 完成度
提交至 App Review 的申请 (包括可供预订的 app) 应为该 app 的*终版本,并应包含所有必要的元数据和有效网址。所有占位符文本、空白网站和其他临时内容应在提交前移除。在提交 app 之前,请务必在设备上对 app 的错误和稳定性进行测试;如果您的 app 需要登录,请提供演示帐户信息 (并打开您的后台服务!)。如果您在 app 中提供了 App 内购买项目,请确保审核人员能够看到这些内容,并确保这些内容处于完整且*新的状态,否则请在审核备注中说明相关原因。请不要将 App Review 视作软件测试服务。我们将拒*不完整的 app 套装以及会出现崩溃或存在明显技术问题的二进制文件。

2.2 Beta 版测试
App 的演示版、beta 版和试用版不适合出现在 App Store 中,请改用 TestFlight。所有通过 TestFlight 提交以进行测试发布的 app 都应旨在公开发布,并应遵循“App Review 准则”。请注意,使用 TestFlight 的 app 不得分发给测试者用以换取任何类型的报酬,包括作为众筹资金的*励。对于 beta 版 app 的大幅更新应先提交至 TestFlight App Review 团队,然后再分发给您的测试者。欲了解更多信息,请访问“TestFlight Beta 测试”。

2.3 准确的元数据
客户应该知道他们在下载或购买您的 app 时会得到什么,所以请确保 app 的描述、屏幕快照和预览能够准确反映 app 的核心体验,并记得不断更新,以便保持与新版本相应的*新状态。

2.3.1 请勿在 app 中包含未记录的功能或隐藏功能;不管是对于*终用户还是 App Review 团队,app 功能都应清晰可见。同样,您不应该在 App Store 或离线情况下,营销您的 app 中实际并不提供的内容或服务 (例如基于 iOS 的病毒和恶意软件扫描工具)。如果出现恶劣或屡教不改的行为,则可能会从 Apple Developer Program 中除名。我们正努力将 App Store 打造成值得信赖的生态系统,并希望我们的 app 开发者也能如此;如果您不诚实以待,我们之间就不会有任何业务往来。
2.3.2 如果您的 app 包含 App 内购买项目,请确保 app 的描述、屏幕快照和预览清楚地指明是否有需要另行购买的精选项目、关卡和订阅等。如果您决定在 App Store 中推广 App 内购买项目,请确保 App 内购买项目的显示名称、屏幕快照和描述适合所有公众,并遵循“推广您的 App 内购买项目”中的准则;此外,您的 app 也应正确使用 SKPaymentTransactionObserver 方法 (英文),以便客户可以在 app 内无缝完成购买。
2.3.3 屏幕快照应展示 app 的使用情况,而非仅显示标题封面、登录页面或初始屏幕。屏幕快照还可以包括文本及图像说明 (例如:演示输入机制,如触控点或 Apple Pencil 的动画),并展示设备上的扩展功能,如触控栏。
2.3.4 预览是让客户了解 app 外观和功能的好方法。为了确保客户理解他们将在 app 中获得的体验,预览只可使用从 app 中采集的视频屏幕。Stickers 和 iMessage 信息扩展可以将用户体验展示在“信息”app 中。您也可以添加旁白和视频,或添加文本说明,以帮助说明任何无法仅通过视频进行阐明的内容。
2.3.5 请为 app 选择*适合的类别,并在需要帮助时参考“App Store 类别定义”。如果选择的类别与实际情况相差较远,我们可能会更改 app 的类别。
2.3.6 请在 App Store Connect 中诚实地回答年龄分级问题,以使 app 与家长控制功能的分级保持一致。如果 app 分级有误,客户在获得 app 时可能会感到诧异,或促使政府监管部门展开相应调查。如果 app 所含的媒体内容要求显示内容分级或警告 (如电影、音乐和游戏等),则需在销售 app 的每个地区内遵循当地要求。
2.3.7 请选择一个独一无二的 app 名称,指定能够准确描述 app 的关键词,不要试图用商标术语、流行 app 的名称或其他不相关的短语来包装任何元数据,以此欺骗系统。App 名称必须限制在 30 个字符以内,且不得包含不属于 app 名称的价格、词语或描述。App 副标题是详细介绍 app 背景信息的*佳之处。副标题必须遵循我们的标准元数据规则,且不得包含不当内容、提及其他 app 或做出无法证实的产品声明。Apple 可以随时修改不合适的关键字或采取其他相应步骤,以防止不当使用。
2.3.8 元数据应适合所有受众,所以请确保您的 app 和 App 内购买项目的相关图标、屏幕快照和预览保持在 4+ 年龄分级;即使您的 app 分级更高,也应如此。例如,如果您的 app 是包含暴力的游戏,请勿选择包含惨烈的死亡或用枪瞄准特定角色的图像。只有“儿童类别”的 app 才能在元数据中使用类似“适合幼儿”和“适合儿童”等词语。请务必确保包括 app 名称和图标 (小图标、大图标、Apple Watch app 和备用图标等) 在内的元数据彼此相似,以免引起困惑。
2.3.9 您应负责确保有权使用 app 图标、屏幕快照和预览中的所有材料,并应显示虚构的帐户信息,而非真实个人的数据。
2.3.10 请确保您的 app 注重 iOS、Mac、Apple TV 或 Apple Watch 体验,并且不在 app 或元数据中包含其他移动平台的名称、图标或图像,除非存在已获批的特定互动功能。
2.3.11 您提交至 App Store 可供预订的 app 必须为完整且可发布的状态。请确保您*终发布的 app 与其可供预订状态时所宣传的内容没有实质性差异。如果您对该 app 进行了重大更改 (例如更改其商业模式),则应重新开始其预订销售。
2.3.12 App 必须在其“新功能”文本中清楚地描述新功能和产品更改情况。一些简单的错误修复、安全更新和性能改进可以通过一般描述来说明,但较为重大的更改必须列明在备注中。
2.4 硬件兼容性
2.4.1 为了确保用户能够充分利用您的 app,iPhone app 应尽量能在 iPad 上运行。我们鼓励您考虑开发通用 app,这样客户就可以在所有设备上加以使用。进一步了解通用 app。
2.4.2 通过设计,使 app 节省能耗。App 不应快速耗尽电池电能、产生过多的热量或对设备资源造成不必要的负担。App 及其中显示的任何第三方广告均不可运行无关的后台进程,如加密货币挖矿。
2.4.3 对于 Apple TV app,应确保用户无需使用除 Siri Remote 或第三方游戏控制器之外的硬件输入,但您可以随意提供增强功能供连接其他外围设备时使用。如果需要用户配备游戏控制器,请务必在元数据中清晰说明,以便用户知晓他们需要额外的设备才能玩游戏。
2.4.4 App 不得建议或要求重新启动设备,或者修改与 app 核心功能无关的系统设置。例如,请勿鼓励用户关闭 Wi-Fi 或停用安全功能等。
2.4.5 对于通过 Mac App Store 分发的 app,还有几个额外要求需要您留意:
(i) 这些 app 必须妥当地沙箱化,并遵循“macOS 文件系统文档 (英文)”。另外,这些 app 只应使用相应的 macOS API 来修改其他 app 存储的用户数据 (如书签、“地址簿”或“日历”条目)。
(ii) 这些 app 必须使用 Xcode 中提供的技术来进行打包和提交;不允许使用第三方安装器。另外,这些 app 必须是单个的自包含 app 安装包,不能将代码或资源安装在共享位置。
(iii) 这些 app 不得自动启动或者在启动时包含其他自动运行的代码,不得在未经同意的情况下登录,也不得大量生成在用户退出 app 后仍在未经同意的情况下继续运行的进程。这些 app 不得将图标自动添加到程序坞中,或在用户桌面上留下快捷方式。
(iv) 这些 app 不得下载或安装独立的 app、kext、额外代码或资源,以向我们在审核过程中看到的 app 添加功能,或进行大幅更改。
(v) 这些 app 不得申请升级至 root 特权或使用 setuid 属性。
(vi) 这些 app 不得在启动时显示许可证屏幕、需要使用许可证密匙或实施自己的拷贝保护措施。
(vii) 这些 app 必须使用 Mac App Store 分发更新;不允许使用其他更新机制。
(viii) 这些 app 应在当前发布的 OS 上运行,不得使用已停用或选装的技术 (如 Java、Rosetta)。
(ix) 这些 app 必须在单个 app 套装内包含所有的语言和本地化支持。
2.5 软件要求
2.5.1 App 仅可使用公共 API,并且必须在当前发布的 OS 上运行。进一步了解公共 APIs (英文)。及时更新您的 app,在未来的操作系统版本中不再支持的任何过时功能、框架或技术皆应被淘汰。App 使用的 API 和框架应该是为了实现预期用途,并在 app 描述中说明集成详情。例如,HomeKit 框架应提供家居自动化服务,HealthKit 则应该用于保持健康和健身目的,并集成在“健康”app 中。
2.5.2 App 应自包含在自己的套装中,不得在指定容器范围外读取或写入数据,也不得下载、安装或执行会引入或更改 app 特性或功能的代码,包括其他 app。仅在特殊情况下,用于教授、开发或允许学生测试可执行代码的教育类 app 可以下载所提供的代码,但这类代码不得用于其他用途。这类 app 必须开放 app 提供的源代码,让客户可以完全查看和编辑这些源代码。
2.5.3 如果 app 传输的病毒、文件、计算机代码或程序会对操作系统和/或硬件功能 (包括推送通知和 Game Center) 的正常运行造成负面影响或导致其中断,则该 app 会被拒*。屡教不改或恶劣的违规行为会导致开发者从 Apple Developer Program 中被除名。
2.5.4 多任务处理 app 只允许在实现预期用途时使用后台服务:VoIP、音频播放、地理位置、任务完成记录和本地通知等。如果 app 使用定位后台模式,请提醒用户,这么做会大幅缩短电池使用时间。
2.5.5 我们将在 IPv6 网络上进行审核。如果您的 app 无法与 IPv6 寻址功能兼容,则可能无法通过审核。
2.5.6 如果 app 会浏览网页,则必须使用相应的 WebKit 框架和 WebKit Javascript。
2.5.7 基于蜂窝移动网络且超过 10 分钟的视频流内容必须使用 HTTP 实时流化,并包含一个 192 kbps 为底线的 HTTP 实时流化。
2.5.8 如果 app 会创建替代的桌面/主屏幕环境,或者模拟多 app 插件体验,则该 app 会遭到拒*。
2.5.9 如果 app 会改变或停用标准开关 (如调高/调低音量和铃声/静音开关) 的功能,或者改变或停用其他的原生用户界面元素或行为,则该 app 会遭到拒*。例如,app 不应屏蔽转向其他 app 的链接,或用户希望以某种特定方式运行的功能。进一步了解如何正确处理链接。
2.5.10 不得提交包含空白广告横幅或测试广告的 app。
2.5.11 SiriKit 和快捷方式
(i) 集成 SiriKit 和快捷方式的 app 只能登记无需其他 app 支持便可处理的意图,而且这个意图应当与用户对所述功能的预期相符。例如,如果您的 app 属于膳食计划 app,则不应融入开始体能训练的意图,即使这个 app 共享了与健身 app 的集成也不可以。
(ii) 确保 plist 中的词汇和短语与您的 app 及它所登记意图的 Siri 功能相符。别名必须与您的 app 或公司名称直接相关,不得使用通用术语或者包含第三方 app 名称或服务。
(iii) 以*直接的方式解析 Siri 请求或快捷方式,不要在请求与实现之间插入任何广告或其他市场营销信息。只有在完成相关任务需要时 (例如让用户指定特定类型的体能训练时),才可以要求解疑。
2.5.12 利用 CallKit 或包含 SMS Fraud 扩展的 app 应该只拦截已确认用于发送垃圾信息的电话号码。具有通话、短信或彩信拦截功能或垃圾信息识别功能的 app 必须在营销文本中清楚标识这些功能,并且说明归入拦截列表和垃圾信息列表的标准。通过这些工具获得的数据不得用于与运行或改进您的 app 或扩展没有直接关联的任何其他目的 (例如,不得出于跟踪或创建用户资料等目的来使用、共享或销售这些数据)。
2.5.13 若有可能,使用人脸识别进行帐户验证的 app 必须使用 LocalAuthentication (英文) (而非 ARKit 或其他人脸识别技术),且必须对未满 13 岁的用户使用备用身份验证方式。
2.5.14 在录像、记录日志或以其他方式记录用户活动时,app 必须征得用户的明确同意,而且要提供清晰的视觉指示。这还包括任何对设备摄像头、麦克风或其他用户输入方式的使用。
2.5.15 能够让用户查看和选择文件的 app 应包含“文件”app 中的项目和用户的 iCloud 文稿。
,

3. 业务
在 App Store 中,您可以通过多种方式让自己的 app 实现盈利。如果您的业务模式并不显而易见,请务必在其元数据和 App Review 备注中加以说明。如果我们无法理解 app 的工作方式,或者 App 内购买项目不是那么一目了然,则审核会有所延误,并可能会导致 app 被拒*。尽管价格由您决定,但是我们不会分发要价明显过高的 app 和 App 内购买项目。对于试图以不合常理的高昂价格欺骗用户的 app,我们将予以拒*。

如果我们发现您试图操纵评论,通过付费、提供*励、经过筛选或伪造反馈来提高排名,或者要求第三方服务代您这样做,我们会采取相应措施以维护 App Store 的公正诚信。采取的措施可能包括将您从 Apple Developer Program 中除名。

3.1 付款
3.1.1 App 内购买项目:
如果您想要在 app 内解锁特性或功能 (解锁方式有:订阅、游戏内货币、游戏关卡、优质内容的访问权限或解锁完整版等),则必须使用 App 内购买项目。App 不得使用自身机制来解锁内容或功能,如许可证密钥、增强现实标记、二维码等。App 及对应元数据不得包含指引客户使用非 App 内购买项目机制进行购买的按钮、外部链接或其他行动号召用语。
App 可以提供 App 内购买货币,供客户在 app 内“打赏”数字内容提供商。
通过 App 内购买项目购买的所有点数和游戏货币不得过期,并且您应确保为所有可恢复的 App 内购买项目设计一套恢复机制。
请务必指定正确的可购买类型,否则您的 app 将被拒*。
App 可为其 App 内购买项目的内容启用赠送功能。此类*品的退款只能返还给原购买者,且*品内容不得更换。
通过 Mac App Store 分发的 app 可托管基于非 App Store 机制的插件或扩展。
提供“战利品箱”或其他随机虚拟物品购买机制的 app 必须在客户购买前,向客户披露每种类型物品的获取几率。
非订阅型 app 在提供完整解锁选项前可以提供按时间计算的免费试用期,方法是在“价格等级 0”中设置非消耗型 IAP 项目,并按照命名约定“XX 天试用”来命名。在开始试用之前,app 必须清楚指明试用期时长、试用期结束后不再能访问的内容或服务,以及用户为获得完整功能而需要支付的任何后续费用。进一步了解如何使用收据 (英文)和设备检查 (英文) 来管理内容访问权限和试用期时长。
3.1.2 订阅:无论属于 App Store 上哪一类别,app 都可以提供自动续订的 App 内购买订阅。在 app 内集成可自动续订的订阅时,请务必遵循下述指导原则。
3.1.2(a) 允许的用途:如果您提供自动续订订阅,则必须为客户提供持续的价值,订阅期必须持续至少七天,并且能够在用户的所有设备上访问。以下并非详尽列表,适当的订阅示例包括:新游戏关卡;连载内容;多玩家支持;持续提供实质性更新的 app;对媒体内容的大型合集或持续更新的访问权限;软件即服务 (SAAS);以及云服务支持。此外:
订阅可与单点式服务一起提供。例如,您可以提供整个影片库的订阅,以及单部影片购买或租赁。
您可以在您的多个 app 和服务中提供跨 app 的订阅项目,但这些订阅不可扩展到第三方的 app 或服务。游戏订阅中提供的游戏必须由该开发者拥有或已受*许可 (例如:非属于游戏发布平台的一部分)。所有游戏都必须直接从 App Store 下载。游戏须避免订阅用户的重复支付,且不应损害非订阅用户的利益。
订阅必须适用于可使用该 app 的所有用户设备。进一步了解在您的多个 app 之间共享订阅项目 (英文)。
App 不得强制要求用户为 app 评级或点评、下载其他 app,或执行其他类似操作,然后才能访问该 app 的功能、内容或者使用该 app。
与所有 app 一样,此类服务订阅应当允许用户直接获得付费购买的项目而无需执行额外任务,如在社交媒体上发帖、上传通讯录,以及在 app 内签到特定次数等。
订阅可以包含消耗性的积分、宝石或游戏内货币等。您也可以提供包含消耗性商品打折权益的订阅 (例如能以优惠价购买宝石包的高级会员资格)。
如果要将现有 app 更改为基于订阅的业务模式,您不得减掉现有用户已付费购买的主要功能。例如,针对新客户引入订阅模式后,已购买“完整游戏解锁”的客户应能够继续访问完整版游戏。
支持自动续期订阅的 app 可以通过提供 App Store Connect 中规定的相关信息,来为客户提供免费试用期。如果您的 app 试图通过虚假信息诱骗用户购买订阅或涉及“诱购”行为,这个 app 会被从 App Store 中移除,您也可能会被从开发者帐户中除名。进一步了解订阅免费试用期。
3.1.2(b) 升级和降级:用户应能获得无缝的升级/降级体验,并且不会出现无意间订阅同一内容的多个不同版本。请查阅关于管理订阅升级和降级选项的*佳做法 (英文)。
3.1.2(c) 订阅信息:在让客户订阅之前,您应当清晰描述付费后的具体权益。每月有几期?云存储容量有多大?具体能访问您的哪些服务?务必清晰地传达“协议、税务和银行业务”下“Apple Developer Program 许可协议”的“附件 2”中所述的要求。
3.1.3(a) “阅读器”App:App 可以允许用户访问先前购买的内容或内容订阅 (具体包括:杂志、报纸、图书、音频、音乐、视频、专业数据库访问权限、VoIP、云存储以及经批准的服务,如课堂管理 app),前提是您同意不会直接或间接引导 iOS 用户使用非 App 内购买项目机制进行购买,并且在您介绍其他购买方式的普通沟通中没有刻意阻止用户使用 App 内购买项目。
3.1.3(b) 多平台服务:跨平台运行的 app 可以允许用户访问用户在别处获取的内容、订阅或功能,包括多平台游戏中的消耗品,前提是这些项目也在 app 中以 App 内购买项目的形式提供。您不得直接或间接引导 iOS 用户使用非 App 内购买机制进行购买,在您关于其他购买方式的一般说明中亦不可刻意阻止用户使用 App 内购买项目。
3.1.4 硬件相关内容:在为数不多的情形中,例如当功能依赖于特定的硬件功能时,app 可在不使用 App 内购买项目的情况下解锁相应功能 (例如,天文 app 会在与望远镜同步后增加功能)。与经过批准的实际产品 (如玩具) 配合使用的可选 app 功能可在不使用 App 内购买项目的情况下解锁特定功能,前提是它同时也提供 App 内购买项目选项。您不得要求用户通过购买无关产品或参与广告或市场活动来解锁 app 功能。
3.1.5(a) App 之外的商品和服务:如果 app 允许用户购买将在 app 之外使用的商品或服务,则必须使用 App 内购买项目以外的购买方式来收取相应款项,如 Apple Pay 或传统的信用卡入口。
3.1.5(b) 加密货币:
(i) 钱包:App 可以协助虚拟货币储值,前提是它们由组织类别帐户的开发者提供。
(ii) 挖矿:App 不可参与虚拟货币挖矿,除非处理过程是在设备外进行的 (例如,云端挖矿)。
(iii) 兑换:App 可以通过经批准的交易所协助加密货币交易或传输,前提是它们是由交易所本身提供的。
(iv) 首次代币发行:App 如支持首次代币发行 (“ICO”)、数字加密货币期货交易以及其他数字加密证券或准证券交易,发布方须为已创立的银行、证券公司、期货经纪商 (“FCM”) 或其他经批准的金融机构,并遵守所有相关法律。
(v) 加密货币 app 不可通过完成任务来提供货币,如下载其他 app、鼓励其他用户下载,以及在社交网络发帖等。
3.1.6 Apple Pay:如果 app 使用 Apple Pay,则在销售任何商品或服务之前,必须先向用户提供所有的基本购买信息,并且必须正确使用 Apple Pay 品牌和用户界面元素,具体要求可参考“Apple Pay 识别标志指南 (英文)”和“Human Interface Guidelines (英文)”。使用 Apple Pay 提供重复付款服务的 app 至少需要披露以下信息:
续订周期的时长;除非被取消,否则续订将会继续
每个周期中会提供哪些服务
将向客户收取的实际费用
如何取消
3.1.7 广告:App 内显示的广告必须与 app 的年龄分级相符,允许用户查看用于引导至这个广告的所有信息 (不要求用户离开 app),并且不可涉及基于敏感用户数据的定向或行为广告。敏感的用户数据包括健康/医疗数据 (如来自 HealthKit API 的数据)、学校和课堂数据 (如来自 ClassKit 的数据),或儿童的数据 (如来自儿童类别的 app 的数据),等等。插播广告、会中断或阻止用户体验的广告必须清楚地表明它们属于广告,不得操纵或欺骗用户轻点它们,并且必须提供可以轻松访问和清晰可见的关闭/跳过按钮,按钮大小要足以让用户轻松解除广告。
3.2 其他业务模式问题
下方列表并非详尽清单,并且您提交的 app 可能会导致我们的政策有所更改或更新,但这里有一些额外的应做事宜和勿做事宜需要您谨记在心:

3.2.1 可以接受
(i) 在您的 app 中,出于购买或促销目的而展示您的其他 app,只要您的 app 不只是简单地罗列其他 app。
(ii) 显示或推荐专为经批准的特定需求而设计的第三方 app (如健康管理、航空以及辅助功能等)。您的 app 应能提供持续不断的编辑内容,这样 app 才不会看起来像是个摆设。
(iii) 在租借期限结束后,禁止访问经批准的特定租借内容 (例如电影、电视节目、音乐、图书);所有其他项目服务不得存在过期时间。
(iv) 钱包凭证可用于付款或接收付款、传输交易或是提供身份验证 (例如电影票、优惠券和 VIP 凭据)。如将钱包凭证用作其他用途,则可能会导致 app 被拒,钱包凭据也有可能被撤销。
(v) 保险类 app 必须免费提供,并且必须遵守 app 发布地区的相关法律,且不得使用 App 内购买项目。
(vi) 经批准的非营利组织可以在他们持有的 App 或第三方 app 内进行筹款活动,前提是这些筹款活动必须遵守所有的 App Review 准则并提供 Apple Pay 支持。这类 app 必须披露资金的计划用途,遵守所有必要的当地和联邦政府法律,并且确保向捐款人提供相应的报税收据。在被要求时,还应向 App Review 团队提供其他信息。向捐款人介绍其他非营利组织的非营利组织平台必须确保 app 中列出的每一家非营利组织都已通过非营利组织批准流程。进一步了解如何成为受批准的非营利组织 (英文)。
(vii) App 可允许个人用户使用非 App 内购买项目机制向另一位个人送赠货币式*物,前提为:a) 送赠方拥有决定是否进行送赠的完全自主权,b) 获赠方收取 100% 的*物金额。然而,*物若在任何时间点对应或包含接收任何数字内容或服务,则必须使用 App 内购买项目。
(viii) App 如用于金融交易,投资或资金管理,发布方应为执行此类服务的金融机构,或必须使用由相应机构根据自身条款与条件提供的公共 API。
3.2.2 不可接受
(i) 创建与 App Store 类似且用于显示第三方 app、扩展或插件的界面,或将其作为热门 app 的合集。
(ii) 通过由硬件或操作系统提供的内置功能 (诸如推送通知、照相机或陀螺仪) 或 Apple 服务 (如 Apple Music 访问或 iCloud 存储) 获利。
(iii) 人为地刷广告展示次数或者广告点进次数的 app,以及主要设计目的在于显示广告的 app。
(iv) 在 app 内为慈善机构和募款方筹集资金,除非您是经批准的非营利组织或依上文 3.2.1 (vi) 规定获得了许可。出于以上目的筹集资金的 app 必须在 App Store 上提供免费下载,并只能在 app 之外筹集,例如通过 Safari 浏览器或短信。
(v) 强行限制 app 的用户群,例如限制特定地区或运营商。
(vi) App 应当允许用户直接获得付费购买的项目而无需执行额外的任务,如在社交媒体上发帖、上传通讯录,以及在 app 内签到特定次数等。App 不得要求用户必须先为 app 评分或点评、观看视频、下载其他 app、点击广告或进行其他类似操作,然后才能访问 app 的功能、内容或使用 app,或者接受现金或其他补偿。
(vii) 人为操纵用户在其他服务中的可见性、状态或排名,除非相关服务的条款和条件允许这样做。
(viii) App Store 中不允许分发协助进行二元期权交易的 app。请考虑使用网页版 app。App 如支持差价合约或其他金融衍生工具 (如外汇) 交易,则必须在提供服务的所有司法管辖区获得相应的许可。
(ix) App 不得强制要求用户为 app 评级或点评、下载其他 app,或执行其他类似操作,然后才能访问 app 的功能、内容或者使用 app。
,

4. 设计
Apple 客户非常看重简洁、雅致、创新且易于使用的产品,这也正是我们希望在 App Store 上看到的。您可尽情提供各种优秀设计,但在 App Store 上被获准发布的 app 至少需要满足以下标准。另请记住,即使在 app 获得批准之后,您也应当对其进行更新,确保 app 能正常工作并持续吸引新客户和现有客户。停止服务或体验下降的 app 随时可能会从 App Store 中被移除。

4.1 抄袭者
请拿出您自己的想法。我们知道您有自己的奇思妙想,那么请将它们付诸实际。请不要简单照搬 App Store 上的热门 app,或只是细微修改其他 app 的名称或 UI,就将其挪为己用。这么做不但有引发知识产权侵权索赔的风险,更会加大在 App Store 中浏览的难度,而且对您的开发者同仁来说也不公平。

4.2 *低功能要求
App 应包含功能、内容和 UI,而不仅仅是一个经过重新包装的网站。如果 app 没有什么实用价值、毫无新意或者不太像是一个 app,那它就不适合出现在 App Store 中。如果 app 不能带来持久的娱乐价值,或只是让人感到毛骨悚然,则无法获得批准。如果 app 只是一首歌曲或一部影片,则应提交到 iTunes Store。如果 app 只是一本书籍或游戏指南,则应提交到 iBooks Store。

4.2.1 使用 ARKit 的 app 应提供丰富而完整的增强现实体验,仅将模型放入 AR 视图或重播动画并不足够。
4.2.2 除了目录类 app 之外,app 不应只包含市场营销材料、广告、网络剪报、内容聚合或链接集合。
4.2.3
(i) App 应能独立工作,无需安装其他 app。
(ii) 确保 app 发布时在其二进制文件中包含有正常运行所需的充足内容。
(iii) 如果 app 需要下载其他资源,请披露下载大小并在下载之前提醒用户。现有 app 在 2019 年 1 月 1 日后提交的所有更新都必须遵循这一准则。
4.2.4 与表盘类似的 Apple Watch app 可能会令人感到困惑,因为用户会认为这些 app 能与各种设备功能 (如轻扫、通知和第三方功能栏) 配合使用。将创意性的时间表现方式用作 app 界面是个好点子 (例如,供冲浪者使用的潮汐时钟),但是如果您的 app 与表盘过于相像,则可能会被我们拒*。
4.2.5 主要用作 iCloud 和 iCloud 云盘文件管理器的 app 需要包含更多的 app 功能,才能获得批准。
4.2.6 利用商业化模板或 app 生成服务创建的 app 将被拒*,除非这个 app 由相应内容的提供商直接提交。这些模板服务若要为不同的客户提供差异化的用户体验,可提供工具来帮助客户自行创建创新的 app,但不应代表客户提交 app。模板提供商也可以考虑创建单一的二进制文件,以汇总或“选取”的模型托管所有客户端内容 (例如:在搜索餐厅的 app 里为每个客户餐厅定制独立的条目或页面,或在聚会活动 app 里为每个客户的活动创建单独的条目)。
4.2.7 远程 App 镜像:如果您的远程桌面 app 用作特定软件或服务的镜像,而不是主机设备的普通镜像,则必须符合以下规定:
(a) 主机设备是归用户所有的个人电脑,并且主机和客户端必须通过本地局域网连接。
(b) 客户端中显示的任何软件或服务应在主机设备屏幕上完整呈现,并且不可使用超出远程桌面传输所需的 API 或平台功能。
(c) 所有帐户的创建和管理均必须从主机设备发起。
(d) 客户端上显示的 UI 不与 iOS 或 App Store 视图类似,不提供商店类界面,也不能供用户浏览、选择或购买用户尚未拥有或授权的软件。为明确起见,在镜像的软件中发生的交易不需要使用 App 内购买,前提是这些交易是在主机设备上处理的。
4.3 重复 App
请不要为同一个 app 创建多个套装 ID。如果您的 app 针对特定位置、运动队、大学等存在不同版本,请考虑提交单个 app,并提供 App 内购买项目以提供不同的功能。同时,请避免继续在已有大量类似 app 的类别下进行开发;App Store 上已经有太多模拟放屁、打嗝声音的 app,以及手电筒和爱经 app。上传大量相似版本 app 的开发者会遭到 Apple Developer Program 的除名。

4.4 扩展
托管或包含扩展的 app 必须遵循“App 扩展编程指南 (英文)”或“Safari 浏览器扩展开发指南 (英文)”,如果可行,还应包含诸如帮助屏幕和设置界面在内的一系列功能。您应当在 app 的市场营销文本中清晰且准确地披露提供了哪些扩展,扩展中不可包含营销、广告或 App 内购买项目。

4.4.1 Keyboard 扩展还需要遵循一些额外的规则。
它们必须:

提供键盘输入功能 (如可输入字符);
如果键盘中含有图像或表情符号,请遵循贴纸准则;
提供切换到下一个键盘的方法;
在没有网络连接和不要求完全访问权限的情况下仍能使用;
收集用户活动数据只是为了改进其 Keyboard 扩展在 iOS 设备上的性能。
它们不得:

启动“设置”之外的其他 app;或者
将键盘按键用于其他行为,例如按住 return 键来启动相机等。
4.4.2 Safari 浏览器扩展必须在 macOS 上的*新版 Safari 浏览器上运行。它们不得干扰系统和 Safari 浏览器 UI 元素,并*不能包含恶意或误导性的内容或代码。违背此规则会遭到 Apple Developer Program 除名。除了正常工作所必需的网站,Safari 浏览器扩展不得要求访问更多网站。
4.4.3 表情贴纸
表情贴纸是让“信息”变得更动态、更有趣的*佳方式,让人们能够以更巧妙、有趣、有意义的方式表达自我。无论您的 app 是含有 Sticker 扩展,还是您要创建单独的表情贴纸包,其内容均不得冒犯用户、造成负面体验或违反相关法律。

(i) 通常,不适合在 App Store 上发布的内容也不适合放入表情贴纸内。
(ii) 考虑地区敏感性,不要在难以接受或者会违反当地法律的国家/地区提供您的表情贴纸包。
(iii) 如果您的表情贴纸含义不易理解,请在审核备注中附上清晰的说明,从而避免导致审核流程的延误。
(iv) 确保您的表情贴纸在您的朋友与家人之外具有相关性;它们不应特定于个人活动、群体或关系。
(v) 您必须对表情贴纸中的内容,持有所有必要的著作权、商标权和形象权及授权许可,不得提交任何未经授权的内容。请记住,您必须能够在要求时提供可核实的文件。若 app 内含有您无权使用的表情贴纸内容,该 app 将从 App Store 中去除,屡次侵权者将从开发者帐户中除名。如果您认为自己的内容遭到其他提供商侵权,请点击此处提交申诉。
4.5 Apple 站点和服务
4.5.1 App 可以使用获批的 Apple RSS Feed (如 iTunes Store RSS Feed),但不能抹除 Apple 站点 (如 apple.com、iTunes Store、App Store、App Store Connect、开发者门户等) 的任何信息,也不能使用这类信息进行排名。
4.5.2 Apple Music
(i) MusicKit API 可以让客户在使用您的 app 时访问自己的订阅。它们旨在为 Apple Music 订阅用户提供轻松简便的音乐播放体验。用户必须能够发起 Apple Music 流媒体播放,并且能够使用“播放”、“暂停”和“跳过”等标准媒体控件来浏览音乐内容。此外,您的 app 不得要求用户通过付款或间接的货币化方式来获取 Apple Music 服务的访问权限 (如 App 内购买项目、广告、要求使用用户信息等)。请勿下载、上传或分享源自 MusicKit API 的音乐文件,除非 MusicKit (英文)文稿中已明确允许。
(ii) 使用 MusicKit API 并不能取代为获得更深入或更复杂的音乐集成而可能需要的授权许可。例如,如果您希望您的 app 在特定时刻播放特定的歌曲,或者创建可以在社交媒体上分享的音频或视频文件,您需要直接联系版权持有人来获得许可 (如同步或改编权利) 和资源。封面插图和其他元数据仅可用于与音乐播放或播放列表相关的用途 (包括展示 app 功能的 App Store 屏幕快照),未经版权持有人明确授权,不得用于任何市场营销或广告目的。在 app 中集成 Apple Music 服务时,请务必遵循“Apple Music 识别标志指南 (英文)”。
(iii) 访问 Apple Music 用户数据 (如播放列表和个人收藏) 的 app 必须在用途字符串中清楚披露这类访问行为。收集的任何数据均不得与第三方分享,也不得用于除支持或改进 app 体验之外的任何其他用途。这类数据不得用于识别用户身份或设备,也不得用于广告定向宣传目的。
4.5.3 不得使用 Apple 服务 (包括 Game Center 或推送通知等) 发送垃圾邮件、进行网络钓鱼,或者向客户发送未经请求的信息。不得尝试进行查找、跟踪、关联、挖掘、获得或利用玩家 ID、别名以及通过 Game Center 获得的其他信息。否则将会遭到 Apple Developer Program 的除名。
4.5.4 App 不得将推送通知列为必需条件,并不能将这项功能用于广告、推广或直接营销用途,或者用来发送敏感的个人或机密信息。不当使用这些服务可能会导致撤销您的权限。
4.5.5 仅以 Game Center 团队批准的方式使用 Game Center 玩家 ID,并不得在 app 中显示或向任何第三方显示。
4.5.6 App 可以在自身和 app 元数据中使用会呈现为 Apple 表情符号的 Unicode 字符。Apple 表情符号不可在其他平台中使用,也不可直接嵌入到您的 app 二进制文件中。
4.6 备选 App 图标
App 可以使用自定图标以传达特定信息 (例如表达对某个运动团队的喜爱),前提是每次更改都由用户发起,并且 app 中应包含恢复至原始图标的设置。所有图标变体必须与 app 的内容相关,并且更改内容在所有系统资源之间应保持一致,以便“设置”和“通知”等位置中显示的图标与新的 Springboard 图标相吻合。这项功能不可用于动态、自动或连续性更改,例如用于反映*新天气信息和日历通知等。

4.7 HTML5 游戏与聊天机器人 (Bot) 等
App 可包含或运行未嵌入二进制文件的代码 (如基于 HTML5 的游戏和聊天机器人等),前提是 app 的主要目的并非代码分发,代码亦没有在商店界面或类似商店的界面中提供,而且相关软件 (1) 为免费软件或需通过 App 内购买项目进行购买;(2) 仅使用标准 WebKit 视图中提供的功能 (例如,它必须在 Safari 浏览器中原生打开和运行,且无需修改也无需其他软件);您的 app 必须使用 WebKit 和 JavaScript Core 来运行第三方软件,且不得试图扩展或披露原生平台 API 给第三方软件;(3) 由已加入 Apple Developer Program 且签署“Apple Developer Program 许可协议”的开发者提供;并且 (4) 遵守各个 App Review 指南中的条款 (例如,不含令人反感的内容;使用 App 内购买项目解锁特性和功能)。在被要求时,您必须提供 app 中所含软件和元数据的索引信息。它必须包含软件提供商的 Apple Developer Program 团队 ID,以及可供 App Review 团队用于确认软件符合上述要求的 URL。

,

5. 法律
只要 app 向某个地区的用户提供,那么就必须遵守该地区的所有法律要求 (如果您不太确定,请与律师联系)。我们知道这些东西非常复杂,但除了下方所列准则以外,同时理解所有本地法律,并确保您的 app 能满足所有法律要求,是您必须承担的责任。当然,如果 app 存在唆使、宣传或鼓励犯罪的行为或明显不负责任的行为,则会被拒*。在发现涉及如方便人口贩卖和/或剥削儿童的 app 的*端情况下,我们将通知有关当局。

5.1 隐私
在 Apple 生态体系中,保护用户隐私总是*要务。您要在处理个人数据时小心谨慎,以确保遵守了隐私保护*佳做法 (英文)、适用的法律和“Apple Developer Program 许可协议 (英文)”中的条款,并满足客户的期望。尤其是:

5.1.1 数据收集和存储
(i) 隐私政策:所有 app 必须在 App Store Connect 元数据栏位和 app 内部包含可轻松访问的隐私政策链接。隐私政策必须明确而清楚地:
指明 app/服务所收集的数据 (若有)、收集数据的方式,以及这些数据的所有用途。
确认与 app 共享用户数据 (遵从这些准则) 的任何第三方 (例如,分析工具、广告网络和第三方 SDK,以及能够访问用户数据的任何母公司、子公司或其他相关实体) 会提供与 app 隐私政策所述及这些准则所要求相同或等同的用户数据保护措施。
解释数据保留/删除政策,并且说明用户可以如何撤销同意和/或请求删除用户数据。
(ii) 许可:收集用户数据或使用数据的 app 必须征得用户的同意。付费功能不得依赖于或要求用户授予访问这些数据的权限。App 还必须为客户提供简单易懂且易于操作的方式来撤销同意。确保您在用途说明中清楚且完整地阐述您对数据的使用。如果 app 依据欧盟《一般数据保护条例》(“GDPR”) 或类似法规,出于合法权益而不经事先同意就收集数据,则必须遵循此类法律的所有条款。进一步了解请求许可 (英文)。
(iii) 数据*少化:App 仅可请求访问与 app 核心功能相关的数据,并且仅可收集和使用完成相关任务所需的数据。若有可能,请使用进程外选取器或共享列表,而不要请求“照片”或“通讯录”等受保护资源的完整访问权限。
(iv) 访问权限:App 必须尊重用户的权限设置,不得操纵、欺骗或强迫用户同意不必要的数据访问。例如,可发布照片到社交网络的 app 不得在允许用户上传照片前要求麦克风访问权限。若有可能,请为不同意的用户提供替代解决方案。例如,如果用户拒*共享位置,请提供手动输入地址的功能。
(v) 帐户登录:如果 app 不包含基于帐户的重要功能,请允许用户在不登录的情况下使用。App 不得要求用户提供个人信息才能正常使用,除非个人信息与 app 的核心功能直接相关,或是法律要求时。如果您的核心 app 功能与特定的社交网络 (如 Facebook、微信、微博或 Twitter 等) 不相关,您必须提供无需登录或其他类似机制的访问权限。调取基本档案信息、分享到社交网络或邀请朋友使用 app 等不视为核心 app 功能。App 还必须包含用于撤销社交网络凭证的机制,以及从 app 内停用 app 与社交网络之间数据访问的机制。App 不可在设备外存储社交网络的凭证或令牌,而且只能使用此类凭证或令牌来在 app 使用期间从 app 本身直接连接社交网络。
(vi) 如果开发者开发的 app 试图暗中收集用户密码或其他用户私人数据,那么开发者会被从 Apple Developer Program 中除名。
(iv) 必须使用 SafariViewController 在显著位置向用户显示信息;不得隐藏这个控制器,也不能被其他视图或图层遮挡。此外,未经用户的知情和同意,app 不得私下利用 Safari 浏览器 ViewController 来追踪用户。
5.1.2 数据使用和共享
(i) 除非法律另有许可,否则您不得未经他人允许而使用、传输或共享他们的个人数据。您必须提供相应的信息,说明以何种方式在哪里使用这些数据。App 收集的数据只有在为了改进 app 或用于广告投放用途 (在遵守 Apple Developer Program 许可协议 (英文)) 的前提下,才能与第三方共享。如果 app 在未经用户同意或未能符合数据隐私保护法律的情况下共享用户数据,则 app 可能会被从销售名单中移除,并且可能会导致您被从 Apple Developer Program 中除名。
(ii) 除非法律另有明确许可,否则未经用户的额外同意,为一个用途而收集的数据不可用于其他用途。
(iii) App 不得试图暗中基于收集的数据构建用户资料,也不得尝试、协助或鼓励他人根据从 Apple 提供的 API 收集的数据,或您所谓以“匿名”、“汇总”或其他不可识别的方式收集的数据来识别匿名用户的身份或重建用户资料。
(iv) 请勿使用来自“通讯录”、“照片”或能访问用户数据的其他 API 的信息来构建联系人数据库,以供自己使用或出售/分发给第三方,也不要收集关于用户设备上安装有哪些 app 的信息,以用于分析或投放广告/市场营销。
(v) 请勿使用通过“通讯录”或“照片”收集的信息来联系用户,除非用户以个人方式明确主动发起联系;请勿包含“全部选择”选项,也不要默认选中所有联系人。在信息发送之前,您必须向用户清楚说明这个信息会如何呈现给收件人 (例如,信息中包含什么内容?发件人显示为谁?)。
(vi) 从 HomeKit API、HealthKit、消费者健康记录 API、MovementDisorder API、ClassKit 或深度图和/或面谱绘制工具 (例如 ARKit、相机 API 或照片 API) 收集的数据,不得用于市场营销、投放广告或基于使用情况进行其他数据挖掘,包括第三方在内。进一步了解实施 CallKit (英文)、HealthKit (英文)、ClassKit (英文) 和 ARKit (英文) 的*佳做法。
(vii) 使用 Apple Pay 的 app 只能与第三方共享通过 Apple Pay 获得的用户数据,以帮助或改进商品或服务的交付。
5.1.3 健康和健康研究
健康、健身和医疗数据特别敏感,涵盖这些领域的 app 必须满足额外的规则,并确保客户隐私受到保护:

(i) App 仅能在获得批准的情况下,出于改进健康管理或健康研究的目的,使用在健康、健身和医疗研究背景下收集的数据 (包括从临床健康记录 API、HealthKit API、“运动与健身”或健康领域人体研究中收集的数据) 或将它披露给第三方,不得用于广告投放、市场营销或基于使用情况进行其他数据挖掘。
(ii) App 不得将虚假或错误数据写入 HealthKit 或其他任何医疗研究/健康管理 App,不得在 iCloud 中存储个人健康信息。
(iii) 开展健康领域人体研究的 app 必须获得参与人员提供的知情同意书,如果涉及未成年人,则必须获得由其家长或监护人提供的知情同意书。上述知情同意书必须涵盖以下内容:(a) 研究的性质、目的和时长;(b) 具体规程,给参与人员带来的风险和益处;(c) 关于保密和数据处理 (包括与第三方共享信息的情况) 的信息;(d) 用于回答参与人员问题的联系人;以及 (e) 退出流程。
(iv) 用于开展健康领域人体研究的 app 必须获得一家独立伦理审查委员会的批准。一经要求,必须提供此类批准的证明。
5.1.4 儿童
出于诸多原因,您在处理儿童的个人数据时必须小心谨慎。我们建议您仔细阅读所有要求,以遵循相关法律,如《儿童在线隐私保护法》(“COPPA”)、和欧盟《一般数据保护条例》(“GDPR”) 和其他国际上适用的同等法律。

App 只能出于遵守适用儿童隐私法规的目的要求用户提供出生日期或家长联系信息,但必须提供一些适用于各年龄层用户的实用功能或娱乐价值。

此外,“儿童类别”中的 app,以及向未成年人收集个人信息 (例如姓名、地址、电子邮件、位置、照片、视频、图画、能否聊天、其他个人数据,或是将永久标识符与以上任何信息组合使用)、传输此类信息或能够共享此类信息的 app,则必须拥有隐私政策,且必须遵守适用的儿童隐私保护法规。为了清楚起见,“儿童类别”的家长监控要求,通常并不完全等同于在这些隐私法规下征得家长的同意后收集个人数据。

5.1.5 定位服务
只有在定位服务与 app 提供的功能和服务直接相关时,才能在 app 中使用定位服务。基于位置的 API 不得用于提供紧急服务,不得对汽车、飞机和其他设备进行自主控制 (小型设备,如轻量无人机和玩具除外),不得遥控汽车防盗系统等。在收集、传输或使用位置数据之前,务必进行通知并获得用户同意。如果 app 会使用定位服务,请务必在 app 中说明相应的原因;请参考“Human Interface Guidelines (英文)”,了解相应的*佳做法。

5.2 知识产权
请确保 app 只包含由您创建或拥有使用许可的内容。如果您已越线并在未经许可的情况下使用了内容,您的 app 可能会被移除。当然,这也意味着如果他人抄袭了您的作品,则他们的 app 也可能会被移除。如果您认为自己的知识产权在 App Store 上受到了其他开发者的侵犯,请通过此网页表格提交权利主张。各个国家/地区的法律互不相同,但请务必避免以下常见错误:

5.2.1 一般性:不得在未经授权的情况下,在 app 中使用受保护的第三方材料 (例如商标、版权作品、专利设计);也不得在 app 套装或开发者名称中包含虚假、抄袭或误导性的演示、名称或元数据。App 提交方应当是拥有或获授权使用知识产权和其他相关权利的个人或法律实体,并且应对提供 app 中的任何服务负责。
5.2.2 第三方站点/服务:如果您的 app 会使用、访问第三方服务、通过访问第三方服务盈利或是显示第三方服务的内容,请确保您获得在该服务的使用条款下进行此类操作的特别许可。如有相应要求,则必须提供相关授权。
5.2.3 音频/视频下载:app 不得促进非法文件共享,或在没有获得这些资源的明确授权的情况下,提供从第三方来源 (如 Apple Music、YouTube、SoundCloud、Vimeo) 保存、转换或下载媒体资源的能力。视频/音频内容流也有可能触犯使用条款,所以请务必在 app 访问这些服务前,进行检查。如有相应要求,则必须提供相关文稿。
5.2.4 Apple 认可:不得误导或暗示 Apple 是 app 的来源或提供商,或者 Apple 以任何形式表示认可其质量或功能。如果您的 app 被选为“编辑选荐”,Apple 将自动显示相应徽章。
5.2.5 Apple 产品:不得创建与现有 Apple 产品、界面 (如 Finder)、app (如 App Store、iTunes Store 或“信息”) 或广告主题外观相似或容易混淆的 app。App 和扩展 (包括第三方键盘和贴纸包) 不得含有 Apple 表情符号。iTunes 音乐预览内容不得用于其娱乐价值 (如用作照片拼贴画的背景音乐或游戏配音) 或其他未获授权的方式。如果 app 显示健身记录圆环,则不应以类似于“健身记录”控件的方式展示“活动”,“锻炼”或“站立”数据。请参考“Human Interface Guidelines (英文)”以了解关于如何使用健身记录圆环的更多信息。
5.3 游戏、赌博和彩票
赌博、游戏和彩票的管理难度大,是 App Store 上受到*多管制的 app 类别之一。只有全面核实了即将发布您的 app 的所有国家/地区的相关法律要求后,才能包含此功能,并且要做好准备此功能的审核流程需要更长的时间。您需要谨记以下事项:

5.3.1 抽*和比赛必须由 app 的开发者赞助。
5.3.2 抽*、比赛和抽彩的正式规则必须在 app 中注明,并且必须明确表示 Apple 不是赞助者,也没有以任何形式参与活动。
5.3.3 App 不得通过 App 内购买项目购买点数或货币,以用于任何种类的真实货币游戏;不得向用户出售彩票或抽彩券;不得在 app 内进行资金转账。
5.3.4 提供真实货币游戏 (例如体育下注、扑克、赌场游戏、赛马) 或彩票的 app 必须在使用该 app 的地区获得必要的许可和批准,且只能在这些地区发布,此类 app 在 App Store 中必须免费提供。App Store 上不允许发布非法的赌博辅助工具,包括记牌器。彩票 app 必须有报酬、几率及*品。
5.4 * App
提供 * 服务的 app 必须利用 NE*Manager API (英文),并且仅可由登记为企业的开发者提供。您必须清楚地声明会收集哪些用户数据,以及将如何使用这些数据。* app 不得违反当地法律,如果您选择在需要 * 许可证的地区发布,则必须在 App Review 注释栏位中提供您的许可证信息。

5.5 开发者行为准则
请尊重每一个人,无论是在 App Store 中回复用户评论、回应客户支持请求时,还是与 Apple 沟通时 (包括您在解决方案中心的回复),都应做到这一点。请勿涉及任何形式的骚扰、歧视、恐吓或霸凌行为,也不要鼓励他人实施任何上述行为。

客户的信任是 App Store 获得成功的基石。App 不得存在以下行为:掠夺用户或试图勒索用户;诱导用户进行非自愿的购买;强迫用户共享不必要的数据;以欺骗的方式抬高价格;针对未交付的功能或内容收取费用;或者在 app 内部或外部实施任何其他操纵行为。

发布日期:2018 年 12 月 19 日

,

提交之后
在 App Store Connect 中提交 app 和元数据之后,您随即就会进入审核流程。请谨记以下几点:

时间:App Review 团队会尽快检查您的 app。不过,如果 app 比较复杂或者存在新的问题,则可能需要更深入的审查和考量。也请记住,如果 app 因为违反同一准则而一再被拒*,或者您曾经试图操纵 App Review 流程,您的 app 将需要更长时间才能完成审核。进一步了解 App Review。
状态更新:App 的当前状态会反映在 App Store Connect 中,所以请多留意此处。
加急请求:如果您遇到了严重的时间问题,可以申请加急审核 (英文)。请仅在您真的需要加快审核时才提出申请,以便其他开发者的加急请求不受影响。如果我们发现您滥用此系统,从此以后我们可能都会拒*您的申请。
发布日期:如果您设定在未来某个日期发布 app,在此日期到来之前,即使这个 app 已获得 App Review 团队的批准,也不会显示在 App Store 上。请注意,您的 app 可能需要长达 24 小时才能显示在所有选定的商店中。
拒*:我们的目标是公平、持续地遵循这些准则,但是人无完人。如果您的 app 被拒*,但您存在疑问,或希望提供其他信息,请使用解决方案中心,以与 App Review 团队直接沟通。这样可以帮助您的 app 出现在商店中,也可帮助我们改进 App Review 流程,并在我们的政策中发现需要阐明的部分。如果您仍对结果不满意,请提交申诉 (英文)。

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速