ラベル IOS DEVELOP from green hand の投稿を表示しています。 すべての投稿を表示
ラベル IOS DEVELOP from green hand の投稿を表示しています。 すべての投稿を表示

讨论区导读


新手看这里,分享+总结关于论坛的使用(10-25更新)
iPhone开发, 全区索引! Last updated: November 16, 2010
iPad及Universal程序总结 Last updated: June 4, 2010
iPhone 开发过程中的一些小技术的总结
GameCenter使用指南(初级)
In App Purchase 个人使用总结

去问答中心提问


问答中心介绍
去问题列表寻找我感兴趣的问题
到问答中心提出新的问题

提交审核:最新审核时间贴




最近看到有很多人在问审核时间到底有多久,零零碎碎的很难供大家参考.

希望大家从现在开始用这个贴子来纪录底由 Waiting for Review 到 Approve 或 Reject 的时间.

就好像以下的 (记得注明是新 app 或者是 update)













新 App 上架 !!! 共 22 天



August 14, 2012 14:31


Apple


Ready for Sale



August 14, 2012 14:20


Apple


Processing for App Store



August 13, 2012 09:24


Apple


In Review



July 22, 2012 22:08


Apple


Waiting For Review



July 22, 2012 22:06


Apple


Upload Received



July 22, 2012 22:05





Waiting For Upload



July 22, 2012 21:35


提交审核:App store审核指南

 App store审核指南(2013年1月29日中文版)

由于前段时间应用被拒好几次,刚好今天有空就重新参考官方文档和几个网络上已有的翻译,更新了下最新的审核指南。本人英语不太好,有些翻译失误的大家指出来,我可以修改。
本文档仅供大家参考。

官方英文审核规则地址:https://developer.apple.com/appstore/resources/approval/guidelines.html
英文数据存储规则地址:https://developer.apple.com/icloud/documentation/data-storage/

本文档整理参考帖子:http://www.cocoachina.com/bbs/read.php?tid=82204&keyword=%C9%F3%BA%CB%D6%B8%C4%CF
参考的博客:http://blog.sina.com.cn/s/blog_62c942d20101cjw8.html

IDP申请:Mac- MDP 图文申请教程

今天申请了Mac Developer Program, 顺便总结一下.这篇文章比较适合以前申请过IDP的用户 ,其它的用户有什么问题也可以
写下来,大家会帮助 你解决!

流程和申请IDP的类似,如果以前申请过IDP的话,那会很容易的.

1 打开这个连接, 会看到下图, 点击Enroll Now,

 


2 出现下图的注册流程界面后, 点击Continue, 

 


3 在下图中,需要你自己进行选择, 根据你是否是一个新的Developer 分为两大类, 因为我已经申请过IDP, 只是想在以前的业务基础上加上mac app的开发 ,因此我做了下面的选择, 各位
可以根据自己的情况选择,

 


4因为我是已注册用户,因此就到了登录页面,输入自己的 帐户和密码就OK了, 

 


5下面就是选择Mac  Developer Program ,点击Continue, 

 


6 由于 已经 在申请IDP的时候填写过相应 的公司信息, 因此就直接到了确定信息这一步了, 
如果是新申请者,请参考qdvictory写的这篇文章

 


7在这一步的时候就可以看到相应的信息了,需要做的事情就是填写 purchase form 并传真给Apple,可以打电话给香港那边催一下, 当然了时间应该也不会太长的.

 

IDP申请:公司申请IDP

1 把你公司营业执照复印一份
2 把这个营业执照复印件随便找个角落写上你们公司的电话和当时给你的Enrollment ID号码
3 要注意,营业执照的地址和你申请的时候填写的地址要一致(中英文翻译无所谓),如果不一致,随传真附带一个简单的证明,说明这个执照的地址和你办公地址的确是一家公司,盖上公章。(这个是为了省麻烦,否则他也会找你要)
4 当时填写的电话号码必须要能接到电话,苹果会派人给你打电话(一般就是香港办公室)
5 把写了enrollment id的营业执照复印件传真到+1 (408) 974-1053 (我当时申请的时候给的是一个澳大利亚的传真号)
6 打电话告诉+852 3002 1310,拨2,报上你邮件里的Follow-up号码,说你营业执照发到美国那边了,麻烦他们帮忙处理下。(这步不是必须,电话里是会说普通话的香港mm)
7 如果可以了,他们会通过邮件给你一个purchase form的pdf让你下载。
8 填好,信用卡号填个人的,能境外支付的卡即可,传真到他们要求的号码,等3天。传真之后也可以打电话或者发邮件到chinadev@asia.apple.com,他也会告诉你等3天。
9 信用卡扣款如果成功,基本就差不多了。 

IDP申请:总结个人经验,史上最完整的IDP申请直到软件上架销售流程

第一:IDP的申请

1.先在iPhone DevCenter上注册成为iphone developer

2.加入iPhone开发程序项目iPhone Developer Program Apply Now

3.打算收费的都建议选择99刀那个,QTY是个数的意思。1就好。

4.选择地区,发现没有china,不要紧,列表最右下方有一个 contact us , 进入新页面,填写“ i wanna join IDP , but i cant find my country in the purchase page”。(我当时就这么写的,也不知道英文对不对)

5.大概一到两天之后你会收到一封chinadev【a】asia.apple.com发来的邮件,附件是一个IDP billing...zip的文件

引用
[pre]感谢您与我们 Apple Developer Connection 联络,并询问有关 iPhone Developer Program 事宜。
为了您可以完成注册及购买 iPhone Developer Program 程序,请仔细填写附件中的表格—— iDP BILLING: Credit Card Processing 表格,并通过以下号码传真至我们的 Billing 团队 :

+1 (408) 862-7602 并注明: iDP Billing[/pre]


6.填写IDP billing 表单的时候,注意,除开签名要手写(可以中文),其他的一定要全英文,不行就拼音。必须非常注意的是,billing address是你信用卡的账单地址,一定要和当时申请信用卡时的地址一致。

7,填好后发传真到指定号码,发完后给chinadev【a】asia.apple.com回一封信,告诉他们你已经传真过了。

引用
您好:[/pre]    我已将表格填好并传真至+1 (408) 862-7602,还请劳烦贵公司工作人员帮忙与Billing 团队确认是否收到了我的传真。不胜感激[/pre]


8.接下来会收到他们的回信,回信内容就是让你等待,耐心等吧。据国内多方信息确认,如果信息全部正确,大约两周左右,你会收到信用卡扣款的信息。(当时扣了我两次,一次1刀,一次99刀),然后收到devprograms【a】apple.com邮件title为iPhone Developer Program Activation Code‏,点击其中的激活码即可激活你的IDP账号。这一部分仔细看HOW TO吧,很详细。将你之前等待时开发的那个小程序用自己的认证放到真机上。

ps:等待的过程中,建议你先开发一个简单的小程序,IDP下来之后有用。

第二:立即填写itunesconnect的信息1.bank info是你的收款账号,国内的大银行都支持,
account type最好选择saving(储蓄账户),
swift code去你的银行要一张电汇信息卡片。
branch id是那个支行的名称,通常写在银行那张
电汇信息卡片的bank address 一栏。(我的中国银行账户即是如此,自己把分行名称提出来就好了)。
还有一个local clearing code,这个是本地清算码,可以打电话问银行。你就问他们银行的清算码是多少就行了。不要说英文,她们搞不明白。

2.contract info , 填写w8ben表单,第六项填写9个0,其他的照实填写就好。填完了保存之后,会收到标题为
Your iTunes W-8BEN Tax Forms‏的邮件,将其中的附件(就是你刚才填写的那个表单的PDF)下载打印出来,手写签名。然后扫描该文件,发邮件至        itmslabeltaxforms【a】apple.com.一天之后会收到回信。
引用
Hello,
Your W-8BEN form has been received, and is completed correctly. You do not need to mail us the original.
If you have any further questions, please don’t hesitate to contact us.


第三:尽快上传应用
1.发布到app store必须使用distribution证书,该证书无法直接发布到你的实机(我当时就被HOW TO骗了)

2. build完之后,登陆itunesconnect上传你的应用,至于uploader怎么使用,我还没明白,先用web方式上传吧。
sku number 随便填吧,都可以.
support url 没有条件给你的app建主页的,可以写自己的BLOG地址.

3.之前的小应用现在能用上了。选择收费吧,这样貌似他们能处理contract effect快点儿。提交完毕之后,进入in review状态。不出问题的话大概一周左右收到邮件通知your application status changed to Ready for sale.

4.一天之后再去看,全部的状态都好了,目前已在除开US地区都可以找到我上传的应用了。


这整个过程耗时近一个月,还算顺利。

IDP申请:

在cocoachina受益良多,现写一个idp申请的图文教程回报cocoachina~ 
图1
 
申请账号后点击图1中的join the iphone developer program
图2
 
点击图2中的enroll now
图3
 
继续点击图3中的enroll now
图4
 
由于之前注册过账号,这里直接先使用已存在账号,点击continue
图5
 
图5中是选是个人idp还是公司还是299$的(299$的没有使用过,不多作介绍,公司的可以多个user,但是发布只能是最高权限的人发布,同时注册时需要提供公司营业执照)
图6
 
图6中就照实添写,注意的是下面内容是和信用卡一样的,地址是账单地址。
图7
 
输入完之后会显示图7的内容,核对后点击continue
图8
 
图9
 
下载图8中的pdf,添写里面的表格,注意,enrollment id,person id,fullname,email,phone要与图8中的一致,如果误关了图8页面请照图9重新打开
pdf可以用ps在上面直接打字,签名可以手写之后照相然后P上。
确认无误后利用网上的免费传真,或者email等方式传过去。
等几天后会在email中收到激活码。继续
图10
 
照图9新建一个用户,并选中用户保存

图11

图12
 
图13

图14


照图10选择国家,图11中选择lookup your bank,图12,13搜索到后选择银行

图15
 
依照图14写银行账号,用户名,钱选USD吧
图16
 
图15确认
图17
 
完成后会出现图16的效果。

小学语文老师教过,读文章要先从头到尾看一遍再细读。
申请IDP时的注意事项(欢迎补充):
1.地址要写申请信用卡时的账单地址
2.一般来说saler名都是信用卡持卡人的名字
3.收钱卡由于在公司向个人汇款,所以银行那边可能会监管,选银行前提前打听清楚,不要再出现钱到了拿不到的问题了
4.传pdf时使用的email: chinadev@asia.apple.com 或免费传真网站 http://faxzero.com/
5.除了签名,如无意外情况全用英文或拼音。。。

入门示例:官方文档

推荐电子书:

思路转换:做java转作iphone的新人

思路转换:从C/C++语言到Objective-C语言

Objective-C,通常写作ObjC和较少用的Objective C或Obj-C,是扩充C的面向对象编程语言。所以有一定C/C++语言基础理解和掌握Objective-C也会相应的快些。这回,我们将比较着学习Objective-C语言,掌握其语法并理解其思想。

语法

让我们先来看看C++和Objective-C中对于类的宣言 :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "BaseClass.h"

class MyClass : public BaseClass
{
public:
                    MyClass();
    virtual         ~MyClass();

    virtual int     GetValue() const;
    virtual void    SetValue(int     inValue);

    bool            IsValid() const;

    static MyClass* GetInstance();

private:
    int             mValue;
    static MyClass* sInstance;
};
Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import "BaseClass.h"

@interface MyClass : BaseClass

{
    int         mValue;

}

- (int)         getValue;
- (void)        setValue:   (int)   inValue;
- (BOOL)        isValid;

+ (MyClass*)    getInstance;

@end
通过比较上面两段代码,从语法的角度上我们看到 Objective-C 语言有以下特点:
  • 用 #import 取代了 #include
#import 相当于 C/C++ 语言中的 #include+#pragma once。当头文件嵌套包含的时候,它的作用就发挥出来了。
当某一头文件已经被读取后,又一次被 #include 的时候,#pragma once 这会跳过该次读取。
比如我们在C/C++语言的头文件中常常这样定义,就是为了实现 #pragma once 而做的 :
1
2
3
#ifndef INCLUDED_BASECLASS_H
#include    "BaseClass.h"
#endif
  • 继承的时候没有限定符
继承都是 public 的。
  • 没有构建和虚构函数
  • 成员变量/函数没有限定符
成员变量缺省是   private  protected  的,而函数是 public 的。
  • 没有const关键字
  • 没有virtual关键字
Objective-C 中函数缺省的就是 virtual 的。
接下来再看看具体的实现 :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include    "MyClass.h"
#include    <assert.h>

MyClass*    MyClass::sInstance = 0;

MyClass::MyClass() : mValue(0)
{
}

MyClass::~MyClass()
{
    mValue = -1;
}

int MyClass::GetValue() const
{
    return (mValue);
}

void MyClass::SetValue(int     inValue)
{
    assert(IsValid());
    mValue = inValue;
}

bool MyClass::IsValid() const
{
    return (0 <= inValue && inValue <= 1000);
}

MyClass* MyClass::GetInstance()
{
    if (sInstance == 0) {
        sInstance = new MyClass();
    }
    return (sInstance);
}
Objective-C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#import "MyClass.h"

static MyClass* sInstance = 0;

@implementation MyClass

- (int)         getValue
{
    return (mValue);
}

- (void)     setValue:  (int)         inValue
{
    NSParameterAssert([self isValid]);
    mValue = inValue;
}

- (BOOL)            isValid
{
    return (0 <= inValue && inValue <= 1000);
}

+ (MyClass*)        getInstance
{
    if (sInstance == 0) {
        sInstance = [MyClass alloc];
    }
    return (sInstance);
}

@end
  • 实例方法
方法前面的“-”是实例方法(类似于C++中的类成员函数)
  • 类方法
前缀为“+”的是类方法(类似于C++中的静态成员函数,或者是全局函数)
  • 类变量
与C/C++语言中的静态变量一样,Objective-C 中的类变量就是以 static 声明的变量。(只在当前定义文件中有效)
如果子类也想参照父类中的类变量的时候,须定义属性参照方法(类方法)。(这与面向对象中的封装概念有所背驰,降低了凝聚度
  • 单一继承
Objective-C 与 Java 语言一样,都是单一继承。
如果想实现多重继承,可以只用类似Java 中 implements 的方法。(Objective-C 中叫做 protocol)
  • 发送消息
Objective-C 中类似于C/C++中函数调用的地方都被称作“发送消息”。调用某个函数,被称为发送了某个消息。其形式如下图所示 :
Objective-C message
Objective-C的发送消息
  • 方法,SEL,方法实现
Objective-C 中方法,SEL型,实现的关系如如下图所示 :
Objective-C method
Objective-C的方法

概念

SEL,IMP的定义

接下来,我们来看看 Objective-C 语言中的头文件 objc.h 的定义 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// objc.h

typedef struct objc_class *Class;

typedef struct objc_object {
  Class isa;
} *id;

typedef struct objc_selector  *SEL;
typedef id      (*IMP)(id, SEL, …);
typedef signed char   BOOL;

#define YES             (BOOL)1
#define NO              (BOOL)0

#ifndef Nil
#define Nil 0   /* id of Nil class */
#endif

#ifndef nil
#define nil 0   /* id of Nil instance */
#endif
id
id和void *并非完全一样。在上面的代码中,id是指向struct objc_object的一个指针,这个意思基本上是说,id是一个指向任何一个继承了Object(或者NSObject)类的对象。需要注意的是id是一个指针,所以你在使用id的时候不需要加星号。比如id foo=nil定义了一个nil指针,这个指针指向NSObject的一个任意子类。而id *foo=nil则定义了一个指针,这个指针指向另一个指针,被指向的这个指针指向NSObject的一个子类。
Objective-C id Object
Objective-C的Object
nil
nil和C语言的NULL相同,在objc/objc.h中定义。nil表示一个Objctive-C对象,这个对象的指针指向空(没有东西就是空)。
Nil
首字母大写的Nil和nil有一点不一样,Nil定义一个指向空的类(是Class,而不是对象)。
SEL
SEL是“selector”的一个类型,表示一个方法的名字。比如以下方法:
-[Foo count] 和 -[Bar count] 使用同一个selector,它们的selector叫做count。
在上面的头文件里我们看到,SEL是指向 struct objc_selector的指针,但是objc_selector是什么呢?那么实际上,你使用GNU Objective-C的运行时间库和NeXT Objective-C的运行运行时间库(Mac OS X使用NeXT的运行时间库)时,它们的定义是不一样的。实际上Mac OSX仅仅将SEL映射为C字符串。比如,我们定义一个Foo的类,这个类带有一个- (int) blah方法,那么以下代码:
1
NSLog (@"SEL=%s", @selector(blah));
会输出为 SEL=blah。说白了SEL就是返回方法名。
这样的机制大大的增加了我们的程序的灵活性,我们可以通过给一个方法传递SEL参数,让这个方法动态的执行某一个方法;我们也可以通过配置文件指定需要执行的方法,程序读取配置文件之后把方法的字符串翻译成为SEL变量然后给相应的对象发送这个消息。
在 Objective-C 运行时库中,selector 是作为数组来管理的。这都是从效率的角度出发:函数调用的时候,不是通过方法名字比较而是指针值的比较来查找方法,由于整数的查找和匹配比字符串要快得多,所以这样可以在某种程度上提高执行的效率。
这样就必须保证所有类中的 selector 须指向同一实体(数组)。一旦有新的类被定义,其中的 selector 也需要映射到这个数组中。
实际情况下,总共有两种 selector 的数组:预先定义好的内置selector数组和用于动态追加的selector数组。
  • 内置selector
简单地说,内置的selector就是一个大的字符串数组。定义在objc-sel-table.h文件中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define NUM_BUILTIN_SELS 16371
/* base-2 log of greatest power of 2 < NUM_BUILTIN_SELS */
#define LG_NUM_BUILTIN_SELS 13

static const char * const _objc_builtin_selectors[NUM_BUILTIN_SELS] = {
    ".cxx_construct",
    ".cxx_destruct",
    "CGColorSpace",
    "CGCompositeOperationInContext:",
    "CIContext",
    "CI_affineTransform",
    "CI_arrayWithAffineTransform:",
    "CI_copyWithZone:map:",
    "CI_initWithAffineTransform:",
    "CI_initWithRect:",
    "CI_rect",
    "CTM",
    "DOMDocument",
    "DTD",
    ...

};
可以看到,数组的大小NUM_BUILTIN_SELS定义为16371。字符串按照字母顺序排序,简单的都是为了运行时检索的速度(二分法查找)。
从定义好的 selector 名称我们可以看到一些新的方法名称,比如 CIConetext,CI开头的方法是由Tiger开始导入的程序库。
每次系统更新的时候,这个数组也是需要更新的。
  • 动态追加selector
另一个用于动态追加的 selector,其定义在 objc-sel.m 和 objc-sel-set.m  文件中
新的 selector 都被追加到 _buckets 成员中,其中追加和搜索使用 Hash 算法。
1
2
3
4
5
6
7
8
static struct __objc_sel_set *_objc_selectors = NULL;

struct __objc_sel_set {
    uint32_t _count;
    uint32_t _capacity;
    uint32_t _bucketsNum;
    SEL *_buckets;
};
IMP
从上面的头文件中我们可以看到,IMP定义为
1
id (*IMP) (id, SEL, …)。
这样说来,IMP是一个指向函数的指针,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其他参数。说白了IMP就是实现方法。
我们取得了函数指针之后,也就意味着我们取得了执行的时候的这段方法的代码的入口,这样我们就可以像普通的C语言函数调用一样使用这个函数指针。当然我们可以把函数指针作为参数传递到其他的方法,或者实例变量里面,从而获得极大的动态性。我们获得了动态性,但是付出的代价就是编译器不知道我们要执行哪一个方法所以在编译的时候不会替我们找出错误,我们只有执行的时候才知道,我们写的函数指针是否是正确的。所以,在使用函数指针的时候要非常准确地把握能够出现的所有可能,并且做出预防。尤其是当你在写一个供他人调用的接口API的时候,这一点非常重要。

方法的定义

在头文件 objc-class.h 中,有方法的定义 :
1
2
3
4
5
6
7
typedef struct objc_method *Method;

struct objc_method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
};
这个定义看上去包括了我们上面说过的其他类型。也就是说,Method(我们常说的方法)表示一种类型,这种类型与selector和实现(implementation)相关。
最初的SEL是方法的名称method_name。char型的method_types表示方法的参数。最后的IMP就是实际的函数指针,指向函数的实现。

Class的定义

Class(类)被定义为一个指向struct objc_class的指针,在objc/objc-class.h中它是这么定义的:
1
2
3
4
5
6
7
8
9
10
11
12
struct objc_class {
  struct objc_class *isa;                /* metaclass */
  struct objc_class *super_class;        /* 父类 */
  const char *name;                      /* 类名称 */
  long version;                          /* 版本 */
  long info;                             /* 类信息 */
  long instance_size;                    /* 实例大小 */
  struct objc_ivar_list *ivars;          /* 实例参数链表 */
  struct objc_method_list **methodLists; /* 方法链表 */
  struct objc_cache *cache;              /* 方法的缓存 */
  struct objc_protocol_list *protocols;  /* protocol链表 */
};
由以上的结构信息,我们可以像类似于C语言中结构体操作一样来使用成员。比如下面取得类的名称:
1
2
3
4
Class cls;
cls = [NSString class];

printf("class name %s\n", ((struct objc_class*)cls)->name);

发送消息与函数调用的不同

Objective-C的消息传送如下图所示 :
Objective-C MessageSystem
Objective-C的消息传送
发送消息的过程,可以总结为以下内容 :
  • 首先,指定调用的方法
  • 为了方法调用,取得 selector
源代码被编译以后,方法被解释为 selector。这里的 selector 只是单纯的字符串。
  • 消息发送给对象B
消息传送使用到了 objc_msgSend 运行时API。这个API只是将 selector 传递给目标对象B。
  • 从 selector 取得实际的方法实现
首先,从对象B取得类的信息,查询方法的实现是否被缓存(上面类定义中的struct objc_cache *cache;)。如果没有被缓
存,则在方法链表中查询(上面类定义中的struct objc_method_list **methodLists;)。
  • 执行
利用函数指针,调用方法的实现。这时,第一个参数是对象实例,第二个是 selector。
  • 传送返回值
利用 objc_msgSend API 经方法的返回值传送回去。

简单地从上面发送消息的过程可以看到,最终还是以函数指针的方式调用了函数。为什么特意花那么大的功夫绕个大圈子呢?1
这些年,随着程序库尺寸的扩大,动态链接库的使用已经非常普遍。就是说,应用程序本身并不包括库代码,而是在启动时或者运行过程中动态加载程序库。这样一来一方面可以减小程序大小,另一方面可以提升了代码重用(不用再造轮子)。但是,随之带来了向下兼容的问题。
如果程序库反复升级,添加新的方法的时候,开发者与用户间必须保持一致的版本,否则将产生运行时错误。一般,解决这个问题是,调用新定义的方法的时候,实现检查当前系统中是否存在新方法的实现。如果没有,跳过它或者简单地产生警告信息。 Objective-C中的respondsToSelector:方法就可以用来实现这样的动作。
但是,这并不是万全的解决方案。如果应用程序与新的动态程序库(含有新定义的API)一起编译后,新定义的API符号也被包含进去。而这样的应用程序放到比较旧的系统(旧的动态程序库)中运行的时候,因为找不到链接符号,程序将不能启动。这就是 win32系统中常见的「DLL地域」。
为了解决这个问题,Objective-C 编译得到的二进制文件中,函数是作为 selector 来保存的。就是说,不管调用什么函数,二进制文件中不会包含符号信息。为了验证 Objective-C 编译的二进制文件是否包含符号信息,这里用 nm 命令来查看。
源代码如下 :
1
2
3
4
5
6
7
8
9
int main (int argc, const char * argv[])
{
    NSString*   string;
    int         length;
    string = [[NSString alloc] initWithString:@"Objective-C"];
    length = [string length];

    return  0;
}
这里调用了 alloc、initWithString:、length 等方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
% nm Test
         U .objc_class_name_NSString
00003000 D _NXArgc
00003004 D _NXArgv
         U ___CFConstantStringClassReference
00002b98 T ___darwin_gcc3_preregister_frame_info
         U ___keymgr_dwarf2_register_sections
         U ___keymgr_global
0000300c D ___progname
000025ec t __call_mod_init_funcs
000026ec t __call_objcInit
         U __cthread_init_routine
00002900 t __dyld_func_lookup
000028a8 t __dyld_init_check
         U __dyld_register_func_for_add_image
         U __dyld_register_func_for_remove_image
...
可以看到,这里没有alloc、initWithString:、length3个方法的符号。所以,即使我们添加了新的方法,也可以在任何新旧系统中运行。当然,函数调用之前,需要使用 respondsToSelector: 来确定方法是否存在。正是这样的特性,使得程序可以运行时动态地查询要执行的方法,提高了 Objective-C 语言的柔韧性。

Target-Action Paradigm

Objective-C 语言中,GUI控件对象间的通信利用 Target-Action Paradigm。不像其他事件驱动的 GUI 系统实现的那样,需要以回调函数的形式注册消息处理函数(Win32/MFC,Java AWT, X Window)。Target-Action Paradigm 完全是面向对象的事件传递机制。
例如用户点击菜单的事件,用Target-Action Paradigm来解释就是,调用菜单中被设定目标的Action。这个Action对应的方法不一定需要实现。目标与Action的指定与方法的实现没有关系,源代码编译的时候不会检测,只是在运行时确认(参考前面消息传送的机制)。
运行时,通过respondsToSelector: 方法来检查实现的情况。如果有实现,那么使用performSelector:withObject:来调用具体的Action,像是下面的代码:
1
2
3
4
5
6
7
8
9
10
11
// 目标对象
id target;
// 具体Action的 selector
SEL action;
...

// 确认目标是否实现Action
if ([target respondsToSelector:actioin]) {
    // 调用具体Action
    [target performSelector:action withObject:self];
}
通过这样的架构,利用 setTarget: 可以更该其他的目标,或者 setAction: 变换不同的Action。实现动态的方法调用。