【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3112|回复: 4

iPhone开发入门—-程序员眼中的iPhone

[复制链接]
发表于 2012-12-4 22:55:58 | 显示全部楼层 |阅读模式
自去年 iPhone 面世以来,开创了移动设备内容服务的一种新的模式—-程序商店(App Store)。它极大地降低了移动设备应用程序开发的成本,即使普通人也能进入这个市场。就像在PC上开发应用程序一样,我们的投入只是一台电脑,一个手机。        截止到目前为止,许多大的电话设备提供商/运营商和软件企业都加入了这个新的模式,Nokia的 Ovi Store (2009年5月26日开始),微软的 Windows Marketplace for Mobile ,Google的 Android Market (2008年10月22日开始)等都已经或者准备进入这个市场了。
        就像以前开发PC上的共享软件一样,许多程序员和小的企业加入了开发队伍的行列。只要有新意捞到你人生的第一桶金不是什么问题。国外的一个22岁开发者只用了20分钟开发了一款叫做Sound Grenade的程序,一个小时的收入就是200美金!!!一个月70,80万人民币轻轻松松啊。要论这个程序,没有什么技术可言,纯粹一个垃圾,可是就是这么一个垃圾程序,却受到很多人的欢迎,这只能说作者有创意了。顺便说一说,程序本身是免费的,主要是靠流量带来的广告收入(和网页广告一个道理)。
        从今天开始,介绍一下 iPhone 应用程序的开发,发布流程,让我们也把自己的创意写成程序,展现一下实力吧。
iPhone开发入门(1)—-程序员眼中的iPhone
        iPhone 不单纯是具有电话功能的 iPod,它的有许多有魅力的地方。作为一个应用程序的开发者,我们首先来看看它的这些特征。
        首先,手机上的按键没有了,应用程序的按键,开关与电话的按键统一了起来。取而代之的是触摸屏技术,应用程序的开发者从此不再受按键的限制,可以自由的设计UI的风格。喜欢把按键放哪就放哪,即使不用按键,类似于PC应用程序的滚动条/拖动条等也可以在触摸屏上实现。
iPhone 中已经提供了从按键到滚动条等一系列的UI控件。当然,你也可以不使用这些控件,而是自己自作独特的UI控件。
        制作iPhone应用程序需要的东西
        首先是开发环境,标注的配置是以下的环境:
  • Mac 电脑(CPU要是Intel的)
  • Mac OS X v10.5(Leopard)或以上的版本
  •                 一台 iPhone 或者 iPod touch
当然你也可以在windows或者linux上安装开发环境。iphonedevonlinux有详细的介绍,使用toolchain在Cygwin或者linux下进行iPhone的开发,如果你想省些钞票或者想更深入的了解 iPhone OS 那么不妨试试它。这一部分,我在以后的章节中会专门介绍。
        另外,开发所必要的软件,SDK,IDE等可以免费从Apple的网上下载。如果你想开发有GPS和照相机或者重力传感器功能的程序,那么需要iPhone 3G,其他一般的程序iPod touch就可以了。另外,如果想要把做成的程序发布出去,还需要到Apple Developer Connection花99美金登录。
Cocoa Touch与Xcode        Cocoa Touch
刚才介绍了开发iPhone应用程序的时候,可以选择许多现成的UI控件。实际使用的过程当中,使用叫做「Cocoa Touch」的程序开发组件库,它类似于windows下开发时所用的MFC,.NET FrameWork。利用 Cocoa Touch,开发者不用考虑设备的特性和画面特性,就可以简单的构筑GUI。
        另外,利用Cocoa Touch,可以开发具有以下iPhone功能的应用程序。
照相功能 利用照相机拍照,并将照片保存到iPhone。
当前位置取得功能 要用iPhone取得当前位置,可以使用 GPS,无线LAN,基站等3种方式。应用程序不用考虑使用哪种方式,系统通过最佳的方式取得现在的位置信息。
Xcode
        Xcode是Mac OS X下的IDE开发环境,也是免费的。主要包含有GUI设计用的「Interface Builder」,iPhone应用程序模拟器,编译器等。
Objective-C语言
iPhone开发的时候,基本使用Objective-C语言。它是扩充C的面向对象编程语言,也是创建Mac OS X应用程序的首选语言。如果你会C或者C++,理解Objective-C应该很快。并且因为Objective-C可以在gcc运作的系统写和编译,你也可以混合Objective-C和C/C++来写程序,或者使用原先的C/C++库。
        并且使用Cocoa Touch来开发程序,自己写的代码量也会相应减少,应为大部分的算法,逻辑部分都被程序库吸收了。
        现在就开始开发iPhone应用程序
        准备好了所有的工具,我们就可以开始开发iPhone应用程序了。当然学习Cocoa Touch,Objective-C语言也是很重要的,这些我以后会有专门介绍。
        在开发自己的应用程序之前,最重要的是什么呢? 是开发程序的知识和技能吗?不是的,最重要的是开发者的激情和创意。有了激情,我们能产生好的创意,有了好的创意,我们才能写出优秀的应用程序

这一回,我们从实际开发所需要的SDK开始,讲解一些基本的设定。
        什么是iPhone SDK上一回我们简单地说明了iPhone的应用程序开发环境Xcode。Xcode本来是Mac上的应用程序开发工具,这里只是导入了开发iPhone应用程序所需的SDK而已。正是因为安装了 iPhone SDK,我们才能通过Xcode来使用Cocoa Touch,在开发中使用MAC下的「iPhone 模拟器」。
        如果你的MAC上没有事先安装Xcode也不要紧,在安装iPhone SDK的同时,Xcode会被一起安装。
        下载iPhone SDK
        iPhone SDK可由Apple Developer Connection免费下载。下载之前需要注册「Apple ID」。如果你之前使用 iTunes 下载音乐,或者在线使用 Apple Store 购买商品,那么你使用之前注册的「Apple ID」就可以了。



Apple Develper Connection



下载iPhone SDK
注册Apple ID


如果你已经有Apple ID的话。点击「Log in」,否则的话点击「Create Apple ID」



注册必要的信息,最好填写英文哦
        登录iPhone Dev Center
用刚做好的Apple ID可以登录iPhone Dev Center



登录好了,就可以下载iPhone SDK了。
        安装iPhone SDK
下载好了,就开始安装吧。打开下载的文件,双击里面的「iPhone SDK.mkpg」文件。



安装iPhone SDK
接下来只需一路确定,下一步,就可以完成了。接下来启动Xcode。
        使用Xcode制作程序
        点击硬盘的Developer→Applications→Xcode.app就可以启动Xcode了。



Xcode的位置
        创建工程
        由Xcode的菜单中选择「文件」→「创建新项目...」。然后在模板中选择「View-Based Application」。



确认左边被选地是「iPhone OS」→「Application」。



Xcode(3.1.2)
        在上面的窗口中可以阅览文件,编辑文件,或者启动「Interface Builder」。
编译与执行
        接下来,可以点击编译,成功后会自动打开iPhone程序模拟器「Simulator ~」。如下图:



iPhone Simulator
 楼主| 发表于 2012-12-4 22:57:52 | 显示全部楼层
第一回:http://www.2cto.com/kf/201110/107927.html我们介绍了开发iPhone应用程序标准的环境配置是基于intel Mac的。虽说现在Mac很便宜,但是仍然大部分人仍然在用windows和linux系统,今天就介绍一下在linux上建立iPhone开发系统。这里采用最新的SDK版本3.1.2(截至到2009/12/01)。        这回主要介绍linux下的安装,配置方法,windows(Cygwin)的配置可以参考这里。
        我的HOST机器环境如下:
         $ uname -a
        Linux localhost.localdomain 2.6.18-1.2798.fc6 #1 SMP Mon Oct 16 14:54:20 EDT 2006 i686 i686 i386 GNU/Linux
        $ gcc -v
        Using built-in specs.
        Target: i386-redhat-linux
        config option: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux
        thread model: posix
        gcc version 4.1.2 20070626 (Red Hat 4.1.2-13)
需要准备的东东:
3.1.2用restore file iPhone1,2_3.1.2_7D11_Restore.ipsw
        iPhone3.1.2 SDK iphone_sdk_3.1.2_with_xcode_3.1.4__leopard__9m2809.dmg
许多网站都介绍过了,这里也使用 toolchain 来建立环境。参考 iphonedevonlinux 。
checkout toolchain
         $ mkdir ~/toolchain
        $ cd ~/toolchain
        $ svn checkout http://iphonedevonlinux.googlecode.com/svn/trunk/ ./
        # 拷贝SDK,firmware文件
$ mkdir -p files/firmware
        $ mv ./iphone_sdk_3.1.2_with_xcode_3.1.4__leopard__9m2809.dmg ./files/
        $ mv ./iPhone1,2_3.1.2_7D11_Restore.ipsw ./files/firmware/
今天(2010/2/9)更新的toolchain已经对应3.1.2版本的SDK了,所以大家不用再给他打补丁了。(多谢网友wzhao)
※ 如果遇到"We need the decryption key for 018-6028-014.dmg."的问题,可以将toolchain.sh中的
DECRYPTION_KEY_SYSTEM=$.....    替换为 DECRYPTION_KEY_SYSTEM="a8a886d56011d2d98b190d0a498f6fcac719467047639cd601fd53a4a1d93c24e1b2ddc6"
因为checkout 下来的toolchain是针对3.0版本的,直接不能使用,所以需要打个补丁。这里下载补丁,然后在toolchain目录下:
$ patch < toolchain.sh.patch
        $ chmod u+x toolchain.sh
安装/编译
        本来执行 ./toolchain.sh all 后会全部给安装和编译的,但是实际上有很多问题,所以我们还是一步一步地来。
# 第一步没有什么问题
$ ./toolchain.sh headers
        # 第二步也顺利通过
$ ./toolchain.sh firmware
        # 第三步也挺顺利
$ ./toolchain.sh darwin_sources
        # 最后一步,这一步需要注意了
$ ./toolchain.sh build
执行最后一步编译gcc-4.2-iphone,在链接的时候会出现以下的错误:
ld: library not found for -lc
        collect2: ld returned 1 exit status
        make[3]: *** [libgcc_s.dylib] error 1
        ....
        make[2]: *** [stmp-multilib] error 2
        rm gcov.pod fsf-funding.pod gfdl.pod gpl.pod cpp.pod gcc.pod
        ....
        make[1]: *** [all-gcc] error 2
        make[1]:leaving dir `/home/xxx/toolchain/toolchain/bld/gcc-4.2-iphone'
        make: *** [all] error 2
         
解决它很简单,在toolchain目录下执行:
cp ./sdks/iPhoneOS3.1.2.sdk/usr/lib/libSystem.B.dylib ./toolchain/bld/gcc-4.2-iphone/gcc/libc.dylib接下来在执行一次 ./toolchain.sh build 就可以了。最后出现下面的画面就是成功了。
It seems like the toolchain built!最后你可以执行 ./toolchain.sh clean 删除编译过程中的文件和 SDK 等文件,你也可以不这么做。
        测试
        接下来,借可以先试试 toolchain/apps/ 下面的测试代码 HelloToolchain。
        编译的过程中可能出现的问题有以下几个::
1. 找不到编译器文件 arm-apple-darwin9-gcc
如果直接在HelloToolchain目录下 make。很可能提示,没有 arm-apple-darwin9-gcc 等命令。这是因为没有设置编译器路径的原因。将下面的语句放入 /etc/profile 内(针对所有用户),或者 .bash_profile 文件中就可以了。
export PATH=/home/xxx/toolchain/toolchain/pre/bin:$PATH2. 编译过程中提示Frameworks,或头文件找不到
Classes/ClockAppDelegate.m:10:38: error: AVFoundation/AVFoundation.h: no such file or directory
        make: *** [Classes/ClockAppDelegate.o] Error 1或者是连接的时候提示:
ld: library not found for -lobjc
        collect2: ld returned 1 exit status
        make: HelloWorldFirst? Error 1首先检查你的makefile文件是否配置好了库文件和头文件路径,比如像是以下的设置:
  # iPhone SDK path
        IPHONESDK = /home/xxx/toolchain/toolchain/sys
        # include path (SDK)
        INCPATH += -I"$(IPHONESDK)/usr/include"
        # include path (gcc)
        INCPATH += -I"$(IPHONESDK)/usr/include/gcc/darwin/4.2"
        CFLAGS  += $(INCPATH) \
        ...
        LDFLAGS += -L"$(IPHONESDK)/usr/lib"
        LDFLAGS += -F"$(IPHONESDK)/System/Library/Frameworks"
        LDFLAGS += -F"$(IPHONESDK)/System/Library/PrivateFrameworks"
        CFLAGS += -F"$(IPHONESDK)/System/Library/Frameworks"
        CFLAGS += -F"$(IPHONESDK)/System/Library/PrivateFrameworks"
如果还是不行,下面有两个方法让你得到最新(3.1.2)的版本库和头文件:
        方法1
在这里下载dyldcache,用scp等工具将其传送到iPhone上,然后执行:
iPhone$ ./dyldcache /System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv6大概解压后有4GB左右的文件,请注意iPhone剩余的容量大小。解压完毕后将 ./out 目录下的文件拷贝到linux上的./toolchain/sys/usr/lib 目录下。
        方法2
如果你还没有iPhone设备,那么可以按照以下的方法由sdk文件中提取库文件。
1. 在这里下载HFSExplorer工具。(windows下使用)
2. 用HFSExplorer打开SDK文件(.dmg文件),在Packages目录下将iPhoneSDKHeadersAndLibs.pkg文件解压到某一目录下。然后拷贝到linux下,比如这里拷贝到/tmp下。
3. 执行以下命令,加压该数据包:
$ cd /tmp
        $ xar -xf iPhoneSDKHeadersAndLibs.pkg Payload
        $ zcat Payload | cpio -i
完成之后,在/tmp目录下会生成几个子目录,这里我们需要的是Platforms目录下的东东。将 ./Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.2.sdk 目录与其子目录拷贝到toolchain的sdks目录下就可以了。
1 $ cp -rp ./Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.2.sdk /home/xxx/toolchain/sdks/
注意 toolchain/sdks/ 目录下已经有 iPhoneOS3.1.2.sdk 目录了,完整覆盖它。通过以上修改后,刚才的 makefile 中的SDK路径需要修改一下,像是下面的样子。
# iPhone SDK path
        IPHONESDK = /home/xxx/toolchain/sdks/iPhoneOS3.1.2.sdk
        ...
--------------------------------------------------------------------------------
接下来,可以编译一下自己的程序,上机测试了。别忘了用ldid签名哦!。比如HelloToolchain是:
1 ldid -S HelloToolchain_

        toolchain for iPhone SDK 3.1.2
         

创建Xcode工程
        现在就让我们开始第一个iPhone应用程序吧。启动Xcode,在Xcode的菜单中点击「文件」→「新项目...」。



从模板中选择「View-Based Application」
        模板选择「View-Based Application」。这回取得开发例子是已经登录到App Store的一款应用程序「BargainSale」,它是自动计算打折后价格的一款应用程序。取名为「BargainSale」后,选择保存。
        保存之后,会基于选择的模板生成工程与源代码文件。我们来看看都有哪些。
        源代码文件


左边的Classes目录中保存了自动生成的.h和.m文件。他们是Objective-C语言的头文件和源代码文件。
XIB文件
XIB文件是记录应用程序画面构成和配置的文件。位于Resources目录下。用Cocoa Touch来开发程序,编辑XIB文件是最基本的。编辑XIB文件的时候,使用「Interface Builder」可以在画面上简单,随意的拖动各种控件。



XIB文件与Interface Builder
资源文件
        其他为了制作应用程序的文件都是资源文件。XIB文件也是资源文件的一种,因为比较重要,就单独罗列出来了。比较简单的应用程序也许不需要什么资源文件,但是随着程序的复杂度提升,做好资源文件的管理也很重要。
Interface Builder
前面已经说到了用Xcode附带的「Interface Builder」来编辑XIB文件。在Xcode中双击XIB文件,就会自动启动Interface Builder。
Interface Builder启动之后,点击Tools→Library可以打开标准容器库帮助。这里罗列了 Cocoa Touch 开发时用到的各种组件。通过 Library→Cocoa Touch Plugin→Inputs & Values,可以更加深入的了解各种组件的使用。



由菜单选择程序库
        比如,表示文字的Label控件,Round Rect Button按钮,Text Field 文字框。你可以选择喜欢的控件拖动到你的配置中。



配置控件        标签
        首先我们来使用表示文字用的「Label」控件。



Label控件
        起初控件缺省的显示Label几个字母,这里我们双击它,将其改为「123456789」。



Text Field
接下来,我们将「Text Field」控件拖动到View视图上。



Text Field
这里的Text Field在实际iPhone使用的时候,单击它就会弹出键盘。标准的键盘是输入文字的,这里因为只是输入价格,所以限定为数字键盘。



如果你想更改Text Field的缺省设定,点击Interface Builder菜单栏的Tools→Inspector。



Inspector
在Inspector内,你可以更改各种控件的属性。



        Inspector的上部有4个并排的tab按钮。设定控件属性的时候,选择最左边的tab。这里Text Field只需要输入数字,所以将键盘种类「Keyboard Type」选择为「Number Pad」就好了。



KeyBoard Type
        Segmented Control
        Segmented Control是一个多选一的按钮。这里,我们使用它来表示各种折扣的比率。



Segmented Control
配置好了,就可以设定不同的选择。首先设置4种折扣率。在Inspector的「Segments」中选择4。



接下来,设定不同折扣的比率。在Segmented Control控件的不同按钮上双击,设定折扣文字。

编译与测试

        到这里为止,我们已经配置了最基本的控件。也许你会留意到这些控件都被放到屏幕的上半部了,当你运行程序的时候你就会明白其中的缘由了。先编译一下看看。在Xcode中点击「编译」,并选择保存当前工程后,就可以开始编译了。
        编译完了之后,启动iPhone模拟器,就可以看到我们刚刚配置好的程序界面了。注意在iPhone模拟器上,是由鼠标代替实际设备上的触摸动作的。
        单击Segmented Control控件,选择20%后来确认一下。或者点击Text Field控件,键盘被表示出来了吧。



就像刚才在Segmented Control中设定的那样,只有数字键盘表示出来了。这个键盘占据了屏幕下方的领域。这也正是我们刚才将所有的控件都配置到屏幕上方的原因。
        如果你将控件配置到了屏幕的下半部分时又使用了键盘,那么这些控件会被键盘遮盖掉。所以当有使用键盘的时候,建议将控件都设置到屏幕上方,否则需要程序动态的更改控件位置,比较麻烦。


这回我们主要学习了控件的配置与使用,下一回我们将具体实现输入价格到打折后价格的计算与表示。如下图:

确认操作与处理
        首先让我们确认一下用户怎样操作控件,程序应该怎样处理这些操作。
        这个应用程序是通过用户输入商品价格,并选择折扣比率,来计算打折后的价格。用户需要以下两步操作 :
  •                 输入商品金额
  •                 选择折扣率
        这之后,程序中计算打折后的金额并表示输出。
Outlet与Action
在我们开始编程之前,需要记住以下两个单词。在以后我们会经常用到它们。
Outlet
通过outlet,我们可以从控件中取出信息,或者将新的信息赋予控件。按照词典上的解释outlet可以理解为插座的意思。界面上配置的每个控件,就像是通过“插座”与界面连接。这里,将程序设置在“插座”内,实现控件与界面间的信息交换。
Action
        Action就是指程序中具体的行为,处理。应用程序将按照Action内实现的内容来处理。比如,「按下按钮后的处理」或者「输入文字后的处理」等等。
        编写程序
        接下来我们就开始写程序了。最初的程序在Interface Builder上编写。
        生成Outlet
刚才已经说到,这个程序中需要编程的控件分别是用户输入商品金额与选择折扣率,以及在画面上显示打折后的金额。就是说,我们需要生成3个Outlet。



File's Owner中表示程序的ICON
在Interface Builder内部,程序的实体用ICON来表示。其中「File's Owner」的ICON就是表示程序实体。在File's Owner中可以生成Outlet。
        选择File's Owner,点击Inspector的最右边的Identity标签。其中「Class Outlets」项目就是Outlet的表格。点击「+」可以追加新的Outlet。



追加Outlet
首先我们创建一个名为「motone」的Outlet,代表商品的原价。第二个为「waribiki」,代表选择的折扣率。最后创建一个名为「kekka」的Outlet,代表打折后的价格,用来放入界面中的控件。像是下图所示:



生成Action
与Outlet一样,ACtion也是由Inspector做成。在刚才的 Class Outlets 之上有「Class Actions」。这里我们只需要处理「表示打折以后的价格」,在Class Actions内追加一个Action就可以了。缺省命名为「myAction1: 」。



追加Action
与控件关联
        接下来,我们将做好的Outlet与控件关联起来。在“File's Owner”ICON上点右键,在出现的窗口上可以看到刚才生成的Outlet和Action。如下图:



每个Outlet的右边都有一个圆圈的选择按钮(鼠标光标移动到其上面后,会变成一个加号),将其拖拽到对应界面上的控件。这之后,从圆圈到控件会有一根线连接起来,控件也会被蓝色的线条框包住。如下图:



关联之后,Outlet的名称的右侧将表示控件的名称。同样的方法将3个控件都与对应的Outlet关联。如果想要取消关联,点击表示部分的×后就可以了。
Action的接续方法与Outlet一样,也是通过拖拽来实现。这里我们就将「myAction1: 」右边的圆圈按钮与对应的Segmented控件关联。如下图:



关联之后,会让你选择具体的行为事件,这里因为是更改折扣比率,所以选择「Value Changed」。



创建文件
        截止到现在,我们还没有写过一行代码。其实,在你将Outlet与控件关联的时候,Interface Builder已经代你写了不少程序了。先让我们来确认一下:
        选择File's Owner,在Interface Builder菜单上点击[File]→[Write Class Files...]保存文件到(BargainSaleViewController.m)。



如果已经有文件存在了,就覆盖它。这样,源代码文件就被保存起来了。我们打开来看看。



Outlet被定义在.h头文件中(BargainSaleViewController.h)。你可以打开它确认一下。「motone」「waribiki」「kekka」3个Outlet,Action「myAction1: 」。
        编写Action
接下来我们来实现具体的Action。打开有「myAction1:」的.m文件(BargainSaleViewController.m)。在「myAction1:」函数内用下面的代码来实现
(IBAction)myAction1:(id)sender {
            int kakaku = [[motone text] intValue];
            switch([waribiki selectedSegmentIndex]){
            case 0:
                kakaku = kakaku * (1.f - 0.2f);
                break;
            case 1:
                kakaku = kakaku * (1.f - 0.3f);
                break;
            case 2:
                kakaku = kakaku * (1.f - 0.4f);
                break;
            case 3:
                kakaku = kakaku * (1.f - 0.5f);
                break;
            default:
                break;
            }
            [kekka setText:[NSString stringWithFormat:@"%d", kakaku]];
        }
之后编译,就可以启动模拟器来测试了。



 楼主| 发表于 2012-12-4 22:59:48 | 显示全部楼层
我们先来分析一下上一回初次接触的Objective-C代码。  (IBAction)myAction1:(id)sender {
            int kakaku = [[motone text] intValue];
            switch([waribiki selectedSegmentIndex]){
            case 0:
                kakaku = kakaku * (1.f - 0.2f);
                break;
            case 1:
                kakaku = kakaku * (1.f - 0.3f);
                break;
            case 2:
                kakaku = kakaku * (1.f - 0.4f);
                break;
            case 3:
                kakaku = kakaku * (1.f - 0.5f);
                break;
            default:
                break;
            }
            [kekka setText:[NSString stringWithFormat:@"%d", kakaku]];
        }

这里的代码是使用Segmented Control实现折扣率变化时的Action。让我们从最初的代码开始。
        取出值
Text Field控件中取得输入值
        首先,我们取出用户输入的商品原价。前面已经介绍过了,控件的值都是通过Outlet来得到的。这里Text Field的Outlet是「motone」,其代码如下:
1 int kakaku = [[motone text] intValue];

等号右边就是通过Outlet得到值的方法。将其赋值到变量kakaku中。
Segmented Control控件中取得值
        接下来我们从Segmented Control控件的Outlet「waribiki」中取得其设定值。这里,我们取出的是Segmented Control控件中的「第几个按钮被按下」。不同的按钮对应不同的折扣率。比如最左边的按钮是20%。
1 [waribiki selectedSegmentIndex]

这里最左边的是索引是0,最右边是3。
Objective-C的语法
        接触过C语言编程的朋友也许很快能适应Objective-C的语法的语法,毕竟它是由C语言演化过来的语言(其中大量继承了Smalltalk语言的思想)。我们以上面两个控件为例,来学习一下它的基本语法。

Objective-C的函数调用
        函数调用首先用 [ ] 来包住实现代码。函数调用的对象叫做接收器(receiver,可以理解为对象实例)。
        用Interface Builder配置的控件Outlet就是接收器。接收器与函数(Objective-C中叫做消息)之间用空格分开。用[ ]括住的一个整体就是一次函数调用。
        你也可以嵌套的使用这样的函数调用形式。比如从Text Field控件中取得输入值的时候,就是先在「motone」中执行了「text」,取出具体的文字对象,然后以其为接收器来执行「intValue」消息。这样,我们最终得到的结果就是一个整形的值。
        计算与表示结果
        接下来我们来计算打折后的价格。由商品原价「kakaku」和由Segmented Control控件得到的打折率需要计算出商品打折后的价格。比如选择最左边20%的时候,计算公式如下:
1 kakaku = kakaku * (1.f - 0.2f);

小数后面的「f」表示「float」。如果将整数作为小数来使用的情况下,使用「1.f」而不是「1f」。
        不同的折扣率需要不同的计算方法,这里使用switch语法来区分各种情形:
         switch([waribiki selectedSegmentIndex]){
        case 0:
            kakaku = kakaku * (1.f - 0.2f);
            break;
        case 1:
            kakaku = kakaku * (1.f - 0.3f);
            break;
        case 2:
            kakaku = kakaku * (1.f - 0.4f);
            break;
        case 3:
            kakaku = kakaku * (1.f - 0.5f);
            break;
        default:
            break;
        }

接下来我们使用Label控件的Outlet「kekka」来表示计算的到得打折扣价格「kakaku」。
1 [kekka setText:[NSString stringWithFormat:@"%d", kakaku]];

与上面的函数调用不同,这里增加了参数。

Objective-C的函数调用

「setText」函数的参数是一个字符串,而「kakaku」变量是一个整数,所以我们先将整数变换为字符串型「NSString」。这里我们使用到了「NSString」的字符串格式函数「stringWithFormat」。最后再通过Label控件的Outlet「kekka」经具体的值表示出来。
在以后的学习中,我们将更加深入地学习Objective-C的各种语法和思想

Objective-C,通常写作ObjC和较少用的Objective C或Obj-C,是扩充C的面向对象编程语言。所以有一定C/C++语言基础理解和掌握Objective-C也会相应的快些。这回,我们将比较着学习Objective-C语言,掌握其语法并理解其思想。
        语法
        让我们先来看看C++和Objective-C中对于类的宣言 :
C++
         #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
         #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 的,而函数是 public 的。没有const关键字
        没有virtual关键字
Objective-C 中函数缺省的就是 virtual 的。接下来再看看具体的实现 :
C++
         #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
         #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的发送消息

方法,SEL,方法实现

Objective-C 中方法,SEL型,实现的关系如如下图所示 :

Objective-C的方法

概念
SEL,IMP的定义
        接下来,我们来看看 Objective-C 语言中的头文件 objc.h 的定义 :
         // 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的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
         #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
         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 中,有方法的定义 :
         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中它是这么定义的:
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语言中结构体操作一样来使用成员。比如下面取得类的名称:
         Class cls;
        cls = [NSString class];
        printf("class name %s\n", ((struct objc_class*)cls)->name);
发送消息与函数调用的不同
Objective-C的消息传送如下图所示 :

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 命令来查看。
        源代码如下 :
         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 等方法。
  % 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,像是下面的代码:
         // 目标对象
id target;
        // 具体Action的 selector
        SEL action;
        ...
        // 确认目标是否实现Action
        if ([target respondsToSelector:actioin]) {
            // 调用具体Action
            [target performSelector:action withObject:self];
        }
通过这样的架构,利用 setTarget: 可以更该其他的目标,或者 setAction: 变换不同的Action。实现动态的方法调用。

--------------------------------------------------------------------------------
1. C/C++语言中用回调函数(callback)的概念来实现程序的动态语义,一般该回调函数都是全局或静态的函数,使用Thunk的方法可以将类的成员函数作为回调函数来使用—利用平台相关的技术将对象实例(this指针)传递给调用端。
 楼主| 发表于 2012-12-4 23:00:57 | 显示全部楼层
画面的构成
Cocoa Touch编程中,一个应用程序里面可以包含多个画面。通过列表选择来显示,或者通过下方的标签来显示,等等。CocoaTouch中将这样一个一个的画面成为 View。
        如果只是创建一个View,不能实现一个完整的应用程序。这里,必须生成 Outlet 和 Action,这样才能将程序与 View 连接起来。比如取得View中配置控件的信息,更改其内容等。像这样,加入View中程序称为 Controller。或者针对与View的「ViewController」。Interface Builder中的「ViewController」就是用在创建 Outlet 和 Action 的「File's Owner」。



View与Controller的关系
        可以看出,多个View就要对于多个ViewController。简单起见,这里我们首先实现一个画面的应用程序。
        控件调整        自动调整功能


位置调节
        用 Interface Builder 配置控件的时候,如上图所示会显示蓝色的虚线。这是建议你放置的最佳位置。有效地利用IDE提供的机能,可以很好地设计出造作简便的View。
        调整控件文字大小
        选择想要更改的控件,在Interface Builder菜单中选择「Font」→「Show Fonts」。如下图所示:



选择字体,大小



调整字体,大小
        文字的大小不可能超过控件的大小。通过选择「Layout」→「Size To Fit」可以是字体大小匹配控件大小。



Size To Fit
各种控件
        这里介绍一些常用的控件。都是通过用户的操作会引起Action的控件。
Round Rect Button        Round Rect Button就是一般的按钮,只是四角为圆角。配置在View上,后可以输入文字。



Round Rect Button的配置
        选择 Action 的时候,「Touch Down」是当按钮被按下的时候发生的Action。



Round Rect Button的Action
                 Switch        Switch就是一个开关控件。具有开和关两个状态,每次切换的时候都会产生Action。



Switch的配置



初期状态设置



Switch的Action—Value Changed
比如,当开关控件的 Outlet 为 [outlet isOn],其Action可以定义为:
                (IBAction)myAction1:(id)sender {
                  if ([sender isOn] == YES) {

                    ...

                    // 开关控件为ON时的处理

Slider

Slider控件的配置


Slider控件的范围设置
Slider的Action为「Value Changed」,即是说当设定值变化的时候就会发生相应的Action。


Slider控件的Action
通过Slider控件的 Outlet 我们可以想下面的代码一样实现Action
- (IBAction)myAction1:(id)sender {
          if ([(UISlider *)sender value] == 0.5f) {
            ...
            // Slider的值为0.5时的处理
  }
        }

添加Action和Outlet
截至到现在,我们已经会在 Interface Builder 中用 File's Owner 添加 Action 和 Outlet , 以及由 Write Class Files生成应用程序文件了。但是,如果在途中添加 Action 或者 Outlet 的时候,原先的 Action 会被覆盖掉,我们不得不重新再用 File's Owner 生成一遍。
        这里,我们来看看左右不使用 Interface Builder,添加 Action 和 Outlet 的方法。
        测试项目
        我们先来创建一个测试用的项目 UITest,其中利用 File's Owner 添加一个 Action 和一个 Outlet。



利用File's Owner生成Action和Outlet
        File's Owner 被选择的状态下点击 Interface Builder 的菜单的「Write Class Files...」,选择 Replace 生成程序文件。
        添加Outlet
        Outlet 被定义在 ViewController 的头文件中。下面是模板项目的 UITestViewController.h 文件。



UITestViewController.h文件中的Outlet与Action定义
        我们可以看到文件中Outlet和Action的定义。与其类似,在定义Outlet1的下面,我们再添加两个Outlet。



添加Outlet
文件保存之后,我们可以通过 File's Owner 来确认是否添加成功:



确认添加的Outlet
添加Action
同样的方法,我们在 UITestViewController.h 中添加两个 Action。分别是myAction2,myAction3。



添加Action
保存之后用 Interface Builder 的 File's Owner 确认。



确认添加的Action
除此之外,Action需要在 UITestViewController.m 中定义其实现。



Action的实现
iPhone键盘
iPhone的键盘占去了整个屏幕的一半,所以基本上都是将 TextField 控件放置到画面的上半部。如果需要在画面下方输入文字,需要另外生成一个View,其上半部是 TextField 控件。当点击下半部的控件时,弹出该View。



iPhone键盘
        关闭键盘的方法
        键盘关闭通过 「Did End On Exit」 Action。将其与 Text Field 控件关联。



与“Did End On Exit”关联
        并且设定键盘右下角的按键为关闭按钮。该按钮缺省是「return」或者是换行,这里我们通过设定 Text Field 控件的Attributes,将「Return Key」设定为「Done」,表示按下该按钮激活上面的「Did End On Exit」 Action



设定Return Key



激活「Did End On Exit」 Action
关闭键盘的按钮
        上面使用的键盘中可以设定退出的按钮,可是在「Number Pad」或者「Phone Pad」中,右下角不存在这样一个按钮。如下图:



Number Pad
这种情况下我们需要自定义一个按钮,用来关闭键盘。如下图所示,这里在Text Field控件「右下角配置一个按钮,并与「Touch Down 」Action关联。



如果想结束输入键盘的输入,使用与 Text Field 关联的 Outlet 来执行以下的操作。
[outlet endEditing:YES];

关联按钮与键盘
        上面添加的按钮只是在键盘出现的时候有效,所以我们试着将其与键盘关联。只有在键盘出现的时候才出现,否则不显示。为了控制按钮,我们需要生成按钮的 Outlet,通过它来控制按钮的显示和隐藏。
        当开始在 Text Field 控件上输入文字的时候,该按钮有效。这时 Text Field 控件的 Action 是「Editing Did Begin」,我们在其中将按钮显示出来(按钮的Outlet变量为button_outlet)。

[button_outlet setHidden:NO];接下来,按键按下的Action中追加按钮隐藏的操作。
[button_outlet setHidden:YES];另外,程序启动后,按钮缺省的状态也应该是隐藏的状态。在 inspector 选择按钮的「Drawing」属性为「Hidden」。        透明按钮
        这里在介绍一种透明按钮的方法。通过点击 Text Field 控件以外领域来关闭键盘。这在没有位置用来设置按钮时挺方便。其设置也非常简单,在 inspector 选择按钮的「Type」属性为「Custom」,这样一来,就可以设置透明的按钮。


设置按钮
        选择了 Custom,变成透明的按钮会覆盖View的上半部。


        通过以上设置,就可以使用透明的按钮了。但是有一点需要留意,设置了这样的按钮以后会覆盖掉其领域下的其他控件,就不能触发其他控件的消息了。所以需要将透明控件的显示顺序至于最低层。像下面选择按钮后,选择Interface Builder菜单的「Layout」→「Send Backward」后就可以了。


设置按钮阶层
        确认对话框
        当需要用户确认操作的时候,需要弹出确认对话框。这里使用 UIActionSheet。首先使用 UIActionSheet 的代理,利用Objective-C 的 protocol 在 UIViewController 中处理。
@interface UITestViewController : UIViewController <UIActionSheetDelegate> {显示对话框
        在 UITestViewController.m 文件的 myAction1 中实现对话框显示。\


         (IBAction)myAction1:(id)sender
        {
            UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"select" delegate:self cancelButtonTitle:@"CANCEL" destructiveButtonTitle:@"OK" otherButtonTitles:nil];
            [actionSheet showInView:self.view];
            [actionSheet release];
        }

用户操作
        具体按钮按下的时候,利用UIActionSheet的接口实现。

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {    if(buttonIndex == 0){        // destructiveButton被按下    }}数据保存
Text Field 控件中输入的数据等应用程序一结束就会自动消失。如果下一次启动还想恢复的话怎么办呢?这里可以使用类似于Windows的注册表一类的方法。(这里只限于设置很少量的数据,对于大的数据建议使用数据库SQLite或Bento)
[[NSUserDefaults standardUserDefaults] setObject:myObj forKey:@"myKey"];                 保存myObj是被保存的数据,myKey是以任意字符串。
[[NSUserDefaults standardUserDefaults] valueForKey:@"myKey"];                 提取myKey指定的数据被取出,放到myObj中。
 楼主| 发表于 2012-12-4 23:03:35 | 显示全部楼层
注册 iPhone Developer Program
要在设备上运行自己的程序,需要在「iPhone Developer Program」上注册。首先登录iPhone Dev Center



iPhone Dev Center
点击上图右侧「iPhone Developer Program」的「Apply now」进入注册画面。在之后的页面中点击「Learn More」→「ApplyNow」,并登录。



注册页面
        登录之后,选择是以个人名义注册(Individual),还是以企业/团体名义注册(Company/Organization),并确认金额和契约。完成注册流程后,过上几天会以邮件的形式通知你接下来的流程,按照要求处理就可以了。
        正事完成注册之前,你可以下载最新的iPhone SDK,更新手头iPhone或iPod touch的固件版本。
        启动程序的准备
        在 iPhone Developer Program 上注册后,就可以按照以下顺序启动我们的应用程序了。
        连接Xcode
将 iPhone 或者 iPod touch 设备与 Xcode 连接。平常,会经常用 iTunes 连接设备,这回使用的是 Xcode。打开 Xcode 菜单中的「窗口」→「组织者(organizer)」。在「DEVICES」中会显示接续设备的信息,如下图:



organizer
在organizer表示的信息中,「Identifier」表示的40位的「Device ID」是需要确认的。
        生成证明
        从应用程序点击「utility」→「Keychain access」。



然后点击「Keychain access」→「证明助手」→「发行证明书...」。



其中在「用户的邮箱地址」中填写注册 Apple ID 时的地址,并在 Common Name 中输入英文的名字。最后选择「保存到硬盘」和「指定对称键情报」后点击「下一步」。



适当选择文件保存的位置。



对称键情报中,确认键的大小为「2048位」,算法是「RSA」后点击「下一步」。



过上一会儿,出现结束画面。刚才保存的文件可以用来请求证明书。
        创建和下载配置文件
        点击 iPhone Dev Center 右边的「Program Portal」。



利用 Program Portal 可以设置 iPhone 或者 iPod touch 设备中的应用程序。有简单的向导,使用起来很方便。
        注册证明书
        如下图,点击左边的「Certificates」 可以注册刚才做好的证明书。



点击「Request Certificate」,在下面的画面中选择请求证明书的文件,最后点击「Submit」。



提交之后被添加到表格中,之后点击「Approve」等待。



之后,表格中显示「Download」按钮,点击它下载证明书。



同时不要忘了下载表格下面的「WWDR intermediate certificate」。之后分别双击这两个下载的文件,在「提交证明书」对话框中选择OK。这之后就可以在Keychain的「证明书」一项中确认添加的证明书了。



设备注册
        接下来注册 iPhone 或者 iPod touch。选择「Devices」的右上角的「Add Device」。



在「Device Name」中输入任意的设备名称。在「Device ID」中输入刚才Xcode中确认的值后就OK了。



生成App ID
接下来点击「App IDs」,来生成AppID。



在「App ID Name」中输入任意的名字,在右边的「App ID」中输入“*”。利用 App ID 将应用程序按不同的组管理起来。如果你输入的「Bundle Identifier」与应用程序中包含的「Bundle Identifier」不一致的话,程序是不会启动的。它主要是为了方便多人开发的项目,对于个人而言没有什么必要。所以这里将 App ID 写作「*」就是说含有任何 Bundle Identifier 的程序等可以运行。
        最后点击 Submit,就完成了注册。
[img][/img]


创建Provisioning Profile
最后来创建Provisioning Profile。选择「Provisioning」点击右上角的「Add Profile」。



在「Profile Name」中输入任意名称。「Certificates」「App ID」「Devices」选择刚才设置好的,随后点击 Submit 创建 Provisioning Profile。



等待一会儿,表格中「Download」显示出来。点击它下载 Provisioning Profile 文件。
        安装Provisioning
打开应用程序程序的 Xcode 项目。由菜单打开「窗口」→「organizer」,拖动刚才创建的Provisioning文件到Provisioning项目中。



项目设定
        接下来,使用安装好的Provisioning来设定应用程序。点击菜单的「项目」→「项目设定」。



点击「编译」。



「Code Signing」中的「代码署名ID」是「Any iPhone OS Device」与「iPhone Developer」的组合。右边选择刚才安装的Provisioning,即「iPhone Developer: My Certificate Name」。
        编译与执行
        全部的设定都完成以后,就可以编译了。可以选择是由「Simulator」执行,还是「Device」在世界设备上运行。



编译完成以后,应用程序自动传输到设备并启动
程序终于编写好了,这一回介绍应用程序的发布流程。通过 App Store 将自己的程序向全世界公开。
        准备工作
        向 App Store 注册自己的程序之前,需要准备以下的东西。
  • 57×57像素的ICON
  •                 512×512像素的ICON (JPEG或TIFF格式)
  • 屏幕截图
        制作ICON
这里的两个图标分别是设备上表示这个应用程序的图标(57×57)和在iTunes的App Store上表示的图标(512×512)。比如下面这两个图标。


        需要注意的是,小的图标(57x57)可以是PNG格式的,而在App Store上用的大的图标(512x512)必须是JPEG或者TIFF的格式。其中小的图标在编译程序的时候作为程序资源已经包含到程序文件中了,而大的图标需要通过别的方式登录到App Store上。
        设置程序中使用的ICON
首先来设置程序中使用的小图标。这里图标文件的名称为「Icon.png」。 打开程序的Xcode项目后,拖动该图标文件到左边的「Resources」目录。


        在弹出的对话框中,选择上面的「拷贝到目的组文件夹(必要的情况下)」,并确认下面的「添加到目标」被选上了。点击添加。


        图标添加到工程中后,需要设定其为应用程序的ICON。点击Resources文件夹下的「Info.plist」,在「Icon file」表中输入图标名称「Icon.png」。


        这样,就完成了程序中图标的设置,编译以后就可以显示出来啦。
        抓屏
        屏幕截图可以通过Xcode的organizer来抓取。设备连接下的情况,从organizer选择「Screenshot」标签。


        点击右下角的「Capture」,就会自动截取连接中设备的屏幕。所以在应用程序启动的时候点击这个按钮就可以了。抓取后可以将图片拖动到适当的地方保存。格式选择JPEG。


        给程序起名
        给程序起个好名字是很重要的。改名字会被显示在主画面的程序图标下面。名字不要太长,否则会被省略掉。语言是英语还是汉语没有关系。


        更改名字
        缺省状态下程序的名称与项目的名称一致。需要更改的时候,编辑刚才设置图标时的Info.plist,其中的「Bundle displayname」就是应用程序的名称。


        其他的设定
        再来看看Info.plist中还能设置什么信息。
  •                 根据程序的界面语言选择那种语言的App Store,使用「Localization native development region」。这里选择「Japan」。
  •                 为了区分不同组织,作者开发的应用程序,使用「Bundle identifier」中的「com.yourcompany」,选取不同的KeyWord。尽量选择与自己独特的内容。
  •                 「Bundle version」中设置程序的版本信息,比如最初发表的时候是「1.0」。


        创建 distribution build
发布在App Store的程序与之前开发中在 iPhone 或者模拟器中测试的程序是不同的。需要用叫做 distribution build 的方式来编译。与之前的编译方式相同的是也需要创建Provisioning。
        创建 Provisioning
上一回创建Provisioning的方式一样,由iPhone Dev Center跳到Program Portal页面,按下面的顺序来设置。
        注册证明书        选择左边的「Certificates」,双击「Distribution」。


        与上一回注册设备的证明书一样的顺序,选择文件后注册。结束之后下载证明书。
创建 Provisioning Profile上一回介绍的一样,选择左边的「Provisioning」后,双击「Distribution」。「Distribution Method」设置为「App Store」,然后输入上一回设置的内容,点击Submit,下载安装创建好的Provisioning Profile。


        项目设定
        为了创建 distribution build,需要向工程中添加新的编译目标。由 Xcode 的菜单点击「项目」→「项目设定」中的「构成」标签。


        选择表中的「Release」,并点击在下的「複製」,生成「Release的拷贝」后,将其名称改为「Distribution」。结束后点击「编译」标签,选择「Distribution」。


        最后,需要在「Any iPhone OS Device」项目上选择刚才安装的Provisioning Profile。
        编译
        返回 Xcode 的主窗口,Active的SDK选择「Device」,Active的构成选择「Distribution」。因为用distribution build编译的文件不能直接在设备上使用,所以我们不能选择「编译并执行」,而是只是点击Xcode的「编译」菜单下的「编译」按钮。


        编译介绍以后,在项目目录下的「build」文件夹下会生成「Distribution-iphoneos」目录。后缀名为app的文件就是编译好的程序文件。在文件上点击右键,选择「压缩为"(项目名).app"」。


        之后,就会在相同目录下生成后缀名为zip的压缩文件。
        发布程序到 App Store
为了将应用程序发布到 App Store 上,需要使用 iTunes Connect。
        连接 iTunes Connect
选择 Program Portal 中的「Distribution」→「App Store」标签。点击 App Store 项目中的「Learn More」,然后点击其中的「Go to iTunes Connect」连接。


        发布程序

        在下右边的「Manage Your Application」。在接下来的画面上点击「Add New Application」。
        如果是第一次发布自己的程序,需要设置程序的语言和开发者的名称。开发者的名称是指用iTunes Connect连接App Store的时候,在右上角表示的名字,这个名字可以是公司的名称,卡发团队的名称,或者是你所开发程序的独一无二的品牌。这两个设置以后不能更改的,所以需要慎重。接下来的画面确认你的程序是否需要加密,一般选择「No」。在接下来的画面「Overview」中输入程序的其他信息,加粗的字体是必须的项目。
  • Application Name - 程序名称
  • Application Description - 程序说明
  • Device - 对应设备。选择对应的设备
  • Primary Category - 程序的分类
  • Copyright - 著作权,开发者的名字等信息
  • Version Number - 在App Store上表示的程序版本。一般与程序中设置的版本一致
  • SKU Number - 产品号码。如果你开发了多个程序,不要与其他程序重复
  • Support URL - 在App Store上表示的技术支持的地址链接
  • Support Email Address - 邮箱地址
        在接下来的画面「Upload」中上传事先准备好的文件。
  • Application - 编译好的应用程序文件(压缩文件,后缀名为zip的那个)
  • Large 512x512 Icon - 512×512像素的图标文件
  • Primary Screenshot - 屏幕截图文件
        选择好后,点击下一步。
        在接下来的「Pricing」画面,设置程序的发布日期,以及发布的国家。
  • Availability Date - 应用程序的发布日期。如果不知道,缺省为上传的日期
  • Price Tier - 应用程序的价格。如果是免费的选择「Free」
        这里,设定发布日期的时候需要留意一件事情。因为上传的程序实体不能立刻发布到 App Store 上,需要内部检测人员的评审,只有通过的才能真正地上传到 App Store 上。这个评审的时间大概是2个星期左右。而上传的信息等会根据你设定的发布日期来显示。所以,如果你设置发布日期为上传的日期,那么广告打出去了(App Store上的首页中显示),而实际的程序却不能下载。到了真正能下载的时候,你的广告已经落的老后了,减少了被点击的几率。所以一般设置发布的日期都比上传的日期晚上2/3周为宜。
        接下来,在「Localization」页面中可以设置一些缺省语言意外的程序说明。
        所有都设置完毕后,最后在「Review」页面中确认,如果没问题就上传吧。之后,会返回到「Manage Your Application」页面,你可以确认程序是否被添加到列表中。如果Status是「In Review」代表你的程序正在被审查,审查结束后等待发卖的时候状态会变为「Ready for Sale」,到了前面设定的发布日期,会自动地发布出去。
        如果 Status 是「Pending Contract」表示申请 iPhone Developer Program 中的帐号手续时存在问题,如果该状态一直持续着,你可以联系ADC,询问具体原因。
iPhone开发的专家
        到此为止 iPhone开发入门 系列已经接近尾声了。如果想要成为iPhone开发领域的专家那么还需要很长的路来走。不过我们已经学会了最起码的环境搭建,简单地程序开发,以及Objective-C语言的基础。对于iPhone上的一个好程序(赚钱的程序)来说,有时并不需要你有多高的程序开发基础,就像第一回我提到的那样,重要的是要有好的创意。
        接下来我还会更加深入地介绍iPhone开发过程中的技巧,知识等。希望得到您的关注
        摘自:易飞扬
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-5-6 20:00

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表