读者需要掌握iOS应用的文件结构、iOS项目对文件的管理、iOS的MVC设计。
 iOS应用通常以main()函数作为入口,从main()函数开始执行,iOS应用在main()函数中调用UIApplicationMain()函数创建UIApplication对象,并为该对象设置应用的程序委托——该程序委托必须实现UIApplicationDelegate,应用程序委托将作为整个iOS应用的核心对象;负责创建应用程序窗口、加载应用程序主界面等重要工作。

本章的重要工作:

  • ①、如何在程序中获取UI界面上的UI控件。只要程序获取了这些UI控件,就可调用这些UI控件的属性、方法来修改和控制他们,这样就可以在程序中动态的修改、更新UI控件的外观。
  • ②、如何为UI空间绑定事件处理方法、通过事件处理方法,可以让UI控件响应用户操作,这样即可让iOS应用能与用户交互。
iOS的SDK(Software Development Kit,软件开发工具集)。

一、创建第一个工程

1、Xcode中的iOS工程模板

  • (1)Application类
  • ①、Master-Detauk Application:可以构建树形结构导航模式应用,生成的代码中包含了导航控制器和表视图控制器等。
  • ②、OpenGL Game:可以构建基于openGL ES的游戏应用。
  • ③、Page-Based Application:可以构建类似于电子书效果的英语,这是一种平铺导航。
  • ④、Single View Application:可以构建简单的单个视图应用。
  • ⑤、Utility Application:可以构建一个空应用程序,它会生成两个视图控制器——主视图控制器和子视图控制器。在iPhone中子视图以模态方式呈现,在iPad中子视图以浮动窗口(popover)的形式呈现。
  • ⑥、Empty Application:可以构建一个空应用程序,需要我们自己添加视图等对象,该模板很少使用。
  • (2)Framework & Library类型
  • iOS开发 应用是否在前台 ios应用程序开发_控件

  • Framework & Library类型的模板可以构建基于Cocoa Touch静态库。
  • (3)、Other类型
  • iOS开发 应用是否在前台 ios应用程序开发_iOS开发 应用是否在前台_02

  • 利用该类型,我们可以构建应用的内置付费内容包(In-App purchase Content)和空工程,是哟给内置付费内容包,可以帮组我们构建家具用内置收费功能的应用。

2、创建工程

iOS开发 应用是否在前台 ios应用程序开发_控件_03

  • (1)、Product Name:工程名字;
  • (2)、Organization Name:组织名字;
  • (3)、Company Identifier:公司标识(很重要)。一般情况下,这里输入的是公司的域名(如com.51work6),这类似于Java中的包命令。
  • (4)、Bundle Identifier:捆绑标识符(很重要)。该标识符由Product Name + Company Identifier构成。因为在App Store发布应用的时候会用到它,所以他的命名不可以重复。
  • (5)、Class Prefix:类的前缀,为生成的类加前缀(如XYZViewController)。
  • (6)、Devices:选择设备。可以构建基于iPhone和iPad的工程,也可以构建通用工程。通用工程是这一个工程在iphone和iPad上都可以使用。
  • (7)、Use Storyboard:工程是否采用故事板技术。
  • (8)、Use Automatic Reference Counting:工程是否采用ARC(自动引用计数)技术。
  • (9)、Include Unit Tests:是否产生单元测试相关的类。

3、iOS项目包含的文件

创建项目成功后,点击Xcode工作区左侧的7个导航图标的最左边的一个图标(快捷键comment+1),即可打开Xcode的“项目导航”面板;

iOS开发 应用是否在前台 ios应用程序开发_iOS_04


iOS开发 应用是否在前台 ios应用程序开发_iOS_05

  • (1)、test:这是一个文件夹,他总是与项目名相同。开发者开发iOS项目所开发的源文件、界面设计文件、资源文件等都处于这个文件夹下。如果有需要,开发者也金额以在该文件夹下自由地创建子文件夹来组织代码。默认情况下该文件加下包含内容如下:
  • ①、项目用到的所有的自定义Objective-C类的.h文件和.m文件。
  • ②、界面设计文件(如果启用了Storyboard,将会包含一个.storyboard文件;否则使用nib界面设计文件将会包含一个会多个.xib文件)。
  • ③、Supporting File:这是位于test目录下的子文件夹,它通常用于保存非Objective-C类的源代码和资源文件。该目录下通常会包含如下四个文件:
  • test-info.plist:该文件是一个属性列表文件,主要保存iOS应用的各种相关信息;
  • InfoPlist.strings:这是一个保存各种字符串的文本文件,该文件主要用于为程序国际化提供支持;
  • main.m:包含main()函数的源程序,应用程序入口;
  • test-Prefix.pch:包含项目中用到的来自外部框架的一些头文件(*.pch文件代表预编译头文件)。通过该文件应用的头文件不属于项目内容,开发者很少需要修改该文件的内容。Xcode将会预编译这些头文件,并在后面的项目构建中持续这种预编译的版本,从而减少选择Bulid或Run菜单项编译项目时所需的时间。
  • (2)、testTests:该文件夹下单元测试的相关类和资源。
  • (3)、Frameworks:该文件用于包含该项目所依赖的框架或库,也可用于包含图像和声音等资源文件。任何添加到该文件夹中的框架或库都会被链接到应用中,这样保证iOS应用可以调用这些框架或库中的类、函数和资源。当创建一个iOS项目时,系统默认会添加UIKit.framework、Foundation.framework、CoreGraphics.framework和XCTest.framework这四个框架。
  • (4)、products:该文件夹下紧紧包含该项目所生成的应用程序。在该文件夹下,可以看到一个重新学习iOS.app文件,这就是该项目所生成的程序。该文件也是我们进行iOS应用开发的最终目的。由于我们还没有编译项目,所以重新学习iOS.app显示为红色,Xcode用红色来标识该文件实际上并不存在。

二、从iOS项目开始

1、Interface Builder简介

控制面板中选中Main.storyboard文件,安霞键盘上的“Delete”键,系统弹出对话框提醒用户是否删除该文件,单击对话框底部“MoveTo Trash(将该文件彻底删除到垃圾箱)”按钮,可彻底删除该文件;点击“Remove Reference(删除引用)”按钮,单击该按钮只是从本项目中取消对该文件的引用(也就是编译项目时不再编译该文件),但文件本身依然保留在项目中。

2、向nib文件添加控件

3、修改控制属性

在XIB文件中,按下键盘上的command+option+1到command+option+6组合键分别可以打开文件检查面板、快速帮助检查器面板、身份检查器面板、属性检查器面板、大小检查器面板和连接检查器面板。而且这个区域的检查器面板是动态改变的。

  • (1)、身份检查器:用于管理界面控件的实现类、恢复ID等标识性属性;
  • (2)、属性检查器:用于管理界面控件的拉伸方式。背景色等外观属性;
  • (3)、大小检查器:用于管理界面控件的宽、高、X坐标、Y坐标等大小、位置的相关属性;
  • (4)、连接检查器:用于管理界面控件与程序代码之间的关联性。

4、UIView支持的属性

UIView可指定下列属性:

iOS开发 应用是否在前台 ios应用程序开发_入门_06

  • (1)、Mode
    Mode属性用于控制该UI控件内图片的对齐方式,以及是否缩放该图片来适应该控件,其属性值支持一个弹出菜单。
  • ①、Center:让图片居中;
  • ②、Scale to Fit:缩放图片,保证图片可以适应该控件;
  • ③、Aspect Fit:保持纵横比缩放图片,保证图片可以适应该控件;
  • ④、Aspect Fill:保持纵横比缩放图片,保证图片可以填充该控件;

例如:

imageView.contentMode = UIViewContentModeScaleAspectFit;
  • (2)、tag
    该属性无须且也不能在程序中动态地修改,该属性指定的属性值将作为该UI控件的唯一标识,当程序需要动态控制某个UI控件的外观或行为时,就需要在程序中获取该UI控件的引用,将诶下来程序就可通过该UI控件的Tag属性值来获取该UI控件。

例如:

imageView.tag = 110;
  • (3)、Interaction
    Interaction部分支持如下两个复选框:
  • ①、User Interaction Enabled:如果勾选该复选框,表明该控件可以支持于用户交互。
  • ②、Multiple Touch:如果勾选该复选框,表明控件需要支持多点触摸事件。多点触摸事件可以支持各种复杂的手势,比如,iOS应用中常见的使用两个手指捏合来进行缩放。

例如:

imageView.multipleTouchEnabled = YES;
imageView.userInteractionEnabled = YES;
  • (4)、Alpha
    该属性用于控制该控件的透明度,其属性值支持0.0~1.0的任意浮点数值,其中,0.0代表完全透明,1.0代表完全不透明。如果设置小于1.0的任意浮点数值,那么该控件将具有半透明效果。

例如:

imageView.alpha = 0.5;
  • (5)、Background
    该属性用于控制该控件的背景颜色,开发者可以为该控件选择任意的背景色。

例如:

imageView.backgroundColor = [UIColor purpleColor];
  • (6)、Drawing
    Drawing区包含如下几个复选框:
  • ①、Opaque:该复选框用于设置该控件是否为“不透明”行为。如果勾选该复选框,表明该控件是“不透明”的控件。如果将某个控件设置为“不透明”的控件,这将通知iOS系统,该控件后面的任何内容都无需绘制,这样iOS系统的绘图方法可以执行一个优化来加速绘图。当程序将控件的Alpha设为小于1.0的值时,这就会将该控件设为半透明行为;如果没有勾选Opaque选项,那么iOS系统出了需要绘制该半透明控件之外,还需要绘制该控件后面的内容,这样系统就需要更多的计算开销;
    例如:
view.opaque = NO;
  • ②、Hidden:该复选框用于控制隐藏该控件,如果勾选该复选框,该控件将处于隐藏状态,用户将看不到该控件。
    例如:
view.hidden = YES;
  • ③、Clears Graphics Context:该选项用于控制清除该控件所覆盖的区域。如果勾选选项之后iOS系统将会先清除该控件所覆盖的区域,然后才开始实际绘制该控件。
    例如:
imageView.clearsContextBeforeDrawing = NO;
  • ④、Clip Subviews:该选项控制是否“裁剪”子控件。当该控件包含多个子控件且这些子控件并未完全包含在当前控件内,如果勾选该复选框,那么只有位于当前控件以内的子控件才会被绘制出来;如果不勾选该复选框,不管那些子控件是否位于该父控件之内,都会被绘制出来。
    例如:
view.clipsToBounds = YES;
  • ⑤、Autoresize Subviews:该选项控制是否“自动调整”子控件大小,当该控件调整大小时,如果勾选该复选框,那么该附件所包含的子控件都会随之自动调整大小;如果不勾选该复选框,那么该控件所包含的子控件不会随着调整大小。
    例如:
view.autoresizesSubviews = YES;

然后在子视图中设置:

subView.autoresizingMask = UIViewAutoresizingFlexibleWidth;//自动调整宽度保证与父视图左边和右边的距离不变
//同理:Height:顶部和底部的距离不变;
//     Top:顶部距离不变;
//     Botton:底部距离不变;
//     LeftMargin:左边距离不变;
//     RightMargin:右边距离不变;
  • (7)、Stretching
    该区域的属性值用于控制UIView的拉伸区域。只有当系统需要在屏幕上调整该控件的大小,并且需要重绘该控件时才需要定义拉伸区域。该属性区可制定X、Y、Width、Height这4个属性值,这4个属性值用于精确控制该控件重绘时的拉伸区域,其中X、Y属性值制定重绘区域的起始位置,Width、Height制定重绘区域的宽度和高度——这4个属性值都是0.0~1.0之间的浮点值。

例如:

view.contentStretch = CGRectMake(0, 0, 320, 10);
  • (8)、获取所有的子视图,对子视图操作:
    父视图:view 子视图:subView
  • ①、添加:
[view addSubview:subView];
  • ②、移除:
[subView removeFromSuperview];
  • ③、插入视图在某个视图之上
[view insertSubview:subView1 aboveSubview:subView2];
  • ④、插入视图在某个视图之下
[view insertSubview:subView1 belowSubview:subView2];
  • ⑤、把视图移到顶层
[view bringSubviewToFront:subView];
  • ⑥、把视图移到底层
[view sendSubviewToBack:subView];
  • ⑦、交换子视图
[view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
  • ⑧、获取所有的子视图
subArray = view.subviews;
  • (9)、改变view的中心点,从而改变位置
view.center = CGPointMake(100, 400);

5、UILabel支持的属性

对于UILabel而言,由于它继承了UIView,因此,它除了可以设置UIView所支持的属性外,UILabel还可额外设置如下属性:

iOS开发 应用是否在前台 ios应用程序开发_复选框_07

  • (1)、Text
    该属性的第一个列表可同于选择不同的文本方式,它支持Plain和Attributed两种设置方式,一般使用Plain方式设置即可。接下来的文本框内的字符串就是该Label所系那是的字符串,该文本框可出入任何字符串。
    例如:
label.text = @"我是好人";
  • (2)、Color
    该属性用于控制该UILabel控件内文本的颜色。
    例如:
label.textColor = [UIColor redColor];
  • (3)、Font
    该属性用于控制该UILabel中文本的字体、字体大小和字体风格。
  • ①、System:设置该UILabel使用系统默认的字体。如果选中该列表项,将不能修改字体设置对话框中的Family、Style、Size等属性;
  • ②、System Bold:设置该UILabel使用系统默认的粗体字体。如果选中该列表项,将不能修改字体设置对话框中的Family、Style、Size等属性;
  • ③、System Italic:设置该UILabel使用系统默认的斜体字体。如果选中该列表项,将不能修改字体设置对话框中的Family、Style、Size等属性;
    例如:
label.font = [UIFont systemFontOfSize:14];
label.font = [UIFont boldSystemFontOfSize:13];
label.font = [UIFont italicSystemFontOfSize:12];
  • (4)、Alignment
    该属性设置该UILabel中文本的对齐方式,它可支持“左对齐”、“右对齐”、“居中对齐”三种对齐方式;
    例如:
label.textAlignment = NSTextAlignmentCenter;
label.textAlignment = NSTextAlignmentLeft;
label.textAlignment = NSTextAlignmentRight;
  • (5)、Lines
    该设置控制该UILabel中文本的行数,其属性值默认为1,用于设置该UILabel只能显示一行文本。
    例如:
label.numberOfLines = 1;
  • (6)、Behavior
    该属性区内包含如下两个复选框:
  • ①、Enabled:该复选框控制该UILabel是否可用,默认都会勾选该复选框,保证该UILabel处于可用状态。如果没有勾选该复选框,那么该UILabel将处于不可用状态,该UILabel控件将显示淡灰色。
    例如:
label.enabled = NO;
  • ②、Highlighted:该复选框控制该UILabel是否处于高亮状态。如果勾选该复选框,则该UILabel将会处于高亮状态,该UILabel控件的文本将以高亮颜色显示。接下来还有属性设置高亮颜色。
    例如:
label.highlighted = YES;
  • (7)、Line Break(NSLineBreakMode)
    该属性控制对UILabel控件内文本的截断。当UILabel控件的字符串内容比较多,而UILabel不足以容纳这些字符串内容时,该属性用于控制系统对UILabel内文本的截断,该属性值可支持如下三个列表之一:
  • ①、Truncate Head:对字符串多余部分的开始部分进行截断。用…代表被截断的文本部分;
  • ②、Truncate Middle:对字符串多余部分的中间部分进行截断。用…代表被截断的文本部分;
  • ③、Truncate Tail:对字符串多余部分的结尾部分进行截断。用…代表截断的文本部分。
    例如:
label.lineBreakMode = NSLineBreakByWordWrapping;
label.lineBreakMode = NSLineBreakByCharWrapping;
label.lineBreakMode = NSLineBreakByClipping;
label.lineBreakMode = NSLineBreakByTruncatingHead;
label.lineBreakMode = NSLineBreakByTruncatingTail;
label.lineBreakMode = NSLineBreakByTruncatingMiddle;
  • (8)、Auto shrink
    该属性控制UILabel内文本的自动收缩。当UILabel控件的字符串比较多时,而UILabel不足以容纳这些字符串内容时,该属性用于控制系统对UILabel内文本进行自动收缩,从而使该UILabel控件可以容纳这些字符串内容。该属性下课支持如下三个列表之一:
  • ①、Fixed Fond Size:设置不缩放。让UILabel控件内文字保持固定大小;
  • ②、设置字体进行缩放,如果勾选该列表项,在该列表项下还可以输入一个范围在0.0~1.0之间的浮点值,该浮点值控制该字体缩放的最小比例。
  • ③、Minimum Font Size:设置字体进行缩放,如果勾选该列表项,在该列表项下还可以输入一个整型值,该整型值控制字体缩放的最小字号。
    例如:
label.adjustsFontSizeToFitWidth = YES;
  • (9)、Highlighted
    该属性支持为该UILabel控件内的文本设置高亮颜色。当勾选了前面的Behavior属性区的Highlighted复选框时,此处设置的高亮颜色才会起作用。
    例如:
label.highlightedTextColor = [UIColor purpleColor];
  • (10)、Shadow
    该属性用于为该UILabel控件内的文本设置阴影颜色,该属性的默认值是不使用阴影。如果程序需要为UILabel控件内的文本设置阴影,可以通过该属性挑选阴影颜色。
    例如:
label.shadowColor = [UIColor yellowColor];
  • (11)、Shadow OffSet
    该属性控制UILabel控件内的阴影文本与正常文本之间的偏移,该属性区需要指定Horizontal和Vertical两个属性值,分别指定阴影文本与正常文本在水平和垂直方向的偏移距。对于Horizontal属性值,如果该属性值大于0,阴影文本相对于正常文本向右偏移;如果该属性值小于0,阴影文本相对于正常文本向左偏移。对于Vertical属性值,如果该属性值大于0,阴影文本相当于正常文本向下偏移;如果该属性值小于0,阴影文本相当于正常文本向上偏移。
    例如:
label.shadowOffset = CGSizeMake(2, 2);

三、MVC

1、从程序入口开始

int main(int argc, char * argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

2、应用程序委托

UIApplication对象代表整个iOS应用程序本身,它是一个全局变量,每个iOS应用只有一个UIApplication对象。无论在程序的什么位置,都可通过如下代码来获取应用程序委托:

AppDelegate* appDelegate = [UIApplication sharedApplication].delegate;

下面应用程序委托类的借口部分:

#import <UIKit/UIKit.h>
@class RootViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate]] >
@property (strong, nonatomic) RootViewController* viewController;
@property (strong, nonatomic) UIWindow *window;
@end
提示:#import和@class:@class具有更好地小效率,使用@class指令只要告诉系统RootViewController是一个类名,而无需导入RootViewController.h整个源文件。#import导入了RootViewController.h整个源文件,可以调用类的方法。

该应用程序委托类中定义如下两个属性:

  • ①、类型为UIWindow的window属性;代表整个iOS应用程序的窗口。对于一个iOS应用而言,应用程序窗口将总是同一个对象,只需要创建一次。在iOS应用的整个生命周期中,应用程序窗口无需改变。
  • ②、类型为RootViewController的viewController属性;代表一个视图控制器,iOS采用严格的MVC设计,当系统创建视图控制器时,通常总会加载一个对应的nib文件(界面设计文件)。换句话说,视图控制器通常关联着一个用户界面。

AppDelegate类是实现了UIApplicationDelegate协议,就需要实现该协议定义的方法,这些方法处理iOS应用的各种生命周期事件。下面是AppDelegate类的实现部分代码:

#import "AppDelegate.h"
#import "RootViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //创建UIWindow对象,并初始化该窗口的大小与主屏幕大小相同
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    self.window.backgroundColor = [UIColor whiteColor];
    //创建RootViewController对象并使用RootViewController界面布局文件来初始化该视图控制器关联的用户界面
    self.viewController = [[RootViewController alloc]initWithNibName:@"RootViewController" bundle:nil];
    //让该程序的窗口加载并显示viewController视图控制器关联的用户界面
    self.window.rootViewController = self.viewController;
    //将该UIWindow对象设为主窗口,并显示出来
    [self.window makeKeyAndVisible];
    return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
    //当应用程序从活动状态转入不活动状态时,系统将会调用该方法
    //通常来说,当应用程序突然被中断(比如电话、短信进来时),系统将会调用该方法。
    //另外,当用户离开该程序,程序开始转入后台状态时也会调用该方法;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
    //通常可通过重写该方法来释放共享资源,保存用户数据,取消定时器。
    //开发者还可通过该方法来保存足够的状态数据,这样保证用户重新启动该应用时能正确恢复当前状态。
    //如果该应用程序支持后台执行,当用户退出时,系统调用该方法而不是调用applicationWillTerminate:方法。
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
    //当应用程序进入前台时将会调用该方法
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
    //当应用程序进入前台并转入活动状态时将会调用该方法
}
- (void)applicationWillTerminate:(UIApplication *)application {
    //当应用程序被终止时,系统将会调用该方法
}
@end

我们重写了- (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions;方法,该方法做了如下事情:

  • (1)、创建并初始化UIWindow对象,该UIWindow对象作为该应用程序的窗口;
  • (2)、创建并初始化RootViewController对象。初始化RootViewController对象时加载名为RootViewController.xib的界面设计文件;
  • (3)、让程序窗口显示RootViewController对象关联的程序界面;
  • (4)、将程序窗口设为主窗口,并将窗口显示出来;

3、理解iOS的MVC

MVC思想:将一个应用分成三个基本部分:Model(模型)、View(视图)、Controller(控制器),这三个部分以最少的耦合协同工作,从而提高应用的可扩展性和可维护性。

  • (1)、Model组件:在进行iOS应用开发时,Model组件通常是一些普通的Objective-C类,这些Objective-C类可用于保存少量的应用程序状态数据。当应用程序的状态数据较多时,可以考虑使用Core Data来构建数据模型。
  • (2)、视图组件:在进行iOS应用开发时,主要使用Interface Builder来创建视图组件。在某些特殊情况下,程序也可能需要在代码中创建页面、修改页面,更可能扩展已有的视图控件。
  • (3)、控制器组件:控制器组件通常由开发者开发的Objective-C类来充当。该控制器组件可以是完全自定义的类(继承NSObject的子类)。但大部分时候,控制器都会继承UIKit框架中的UIViewController基类,通过继承该基类,可以让控制器类免费获取大量的功能,并且不再需要重新设计类结构。

4、掌握UIViewController控制器

UIViewController包含如下常见的需要重写的方法:

  • (1)、- (void)viewDidLoad;当控制器管理的视图被装载完成后,系统调用该方法。如果开发者需要在视图装载完成后执行某些代码,即可通过重写该方法来完成。重写该方法不要忘记通过[super viewDidLoad];代码来调用UIViewController基类的viewDidLoad方法;
  • (2)、- (void)didReceiveMemoryWarning;该方法并不会由程序员自己来调用。当系统检测到可用内存紧张时,将会调用该方法。如果开发者需要在系统内存紧张时释放部分内存,则可通过重写该方法来释放那些暂时不会使用的对象所占用的内存。重写该方法时不要忘记通过[super didReceiveMemoryWarning];代码来调用UIViewController基类的didReceiveMemoryWarning方法;
  • (3)、- (void)viewWillAppear:(BOOL)animated;当该控制器管理的视图将要显示出来时,系统自动调用该方法。如果开发者需要在视图将要显示出来时执行某些代码,即可通过该方法来完成。重写该方法时不要忘记通过[super viewWillAppear:YES];代码来调用UIViewController基类的viewWillAppear:方法;
  • (4)、- (void)viewDidAppear:(BOOL)animated;当该控制器管理的视图显示出来后,系统自动调用该方法。如果开发者需要在视图将要显示出来时执行某些代码,即可通过重写该方法来完成。重写该方法的时不要忘记通过[super viewDidAppear:YES];代码来调用UIViewController基类的viewDidAppear:方法;
  • (5)、- (void)viewWillDisappear:(BOOL)animated;当该控制器管理的视图将要被隐藏或将要被移除窗口时,系统自动调用该方法。如果开发者在视图将要被隐藏或将要被移除窗口时执行某些代码,即可通过重写该方法来完成,重写该方法时不要忘记通过[super viewWillDisappear:YES];代码来调用UIViewController基类的viewWillDisappear:方法;
  • (6)、- (void)viewDidDisappear:(BOOL)animated;当控制器管理的视图被隐藏或被移除窗口之后,系统自动调用该方法。如果开发者需要在视图被隐藏或被移除窗口之后执行某些代码,即可通过重写该方法来完成。重写该方法时不要忘记通过[super viewDidDisappear:YES];代码来调用UIViewController基类viewDidDisappear:方法;
  • (7)、- (void)viewWillLayoutSubviews;当该控制器管理的视图将要排列它包含的所有子视图时,系统自动调用该方法。如果开发者需要在视图将要排列它包含的所有子视图时执行某些代码,即可通过重写该方法来完成。重写该方法时不要忘记通过[super viewWillLayoutSubviews];代码来调用UIViewController基类的viewWillLayoutSubviews方法;
  • (8)、- (void)viewDidLayoutSubviews;当该控制器管理的视图把它包含的所有子视图排列完成后,系统自动调用该方法。如果开发者需要在视图把它包含的所有子视图排列完成后执行某些代码,即可通过重写该方法来完成。重写该方法时不要忘记通过[super viewDidLayoutSubviews];代码来调用UIViewController基类的viewDidLayoutSubviews方法;
  • (9)、- (void)loadView;当控制器管理的视图的view为nil的时,系统自动调用该方法。如果开发者需要自定义视图的view时,可以重写该方法。如果不需要自定义视图view时,重写需要通过[super loadView];代码调用UIViewController基类的loadView方法;此方法用于以编程的方式创建view的时候用到。

例如:在自定义view的时候需要重写:

- (void)loadView{
    NSLog(@"--loadView--");
    UIView *view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
    [view setBackgroundColor:[UIColor yellowColor]];
    self.view = view;
}

如果不需要自定义的时,重写时:

- (void)loadView{
    [super loadView];
    NSLog(@"--loadView--");
}
  • (10)、- (void)viewWillUnload NS_DEPRECATED_IOS(5_0,6_0);
  • (11)、- (void)viewDidUnload NS_DEPRECATED_IOS(3_0,6_0);当系统内存吃紧的时候会调用该方法(注:viewController没有被dealloc),内存吃紧在iphone OS 3.0之前didReceiveMemoryWarning是释放无用内存的唯一方法,但是OS 3.0及以后viewDidUnload方法是更好地方式
    视图调用顺序:
2014-12-18 11:29:57.471 test[1827:58110] 1:--loadView--
2014-12-18 11:29:57.473 test[1827:58110] 1:--viewDidLoad--
2014-12-18 11:29:57.474 test[1827:58110] 1:视图将要出现
2014-12-18 11:29:57.476 test[1827:58110] 1:视图将要排列子视图
2014-12-18 11:29:57.476 test[1827:58110] 1:视图已经排列子视图
2014-12-18 11:29:57.480 test[1827:58110] 1:视图将要排列子视图
2014-12-18 11:29:57.480 test[1827:58110] 1:视图已经排列子视图
2014-12-18 11:29:57.508 test[1827:58110] 1:视图已经出现
2014-12-18 11:29:59.972 test[1827:58110] 2:--loadView--
2014-12-18 11:29:59.973 test[1827:58110] 2:--viewDidLoad--
2014-12-18 11:29:59.974 test[1827:58110] 1:视图将要消失
2014-12-18 11:29:59.975 test[1827:58110] 2:视图将要出现
2014-12-18 11:29:59.976 test[1827:58110] 2:视图将要排列子视图
2014-12-18 11:29:59.976 test[1827:58110] 2:视图已经排列子视图
2014-12-18 11:29:59.976 test[1827:58110] 2:视图将要排列子视图
2014-12-18 11:29:59.976 test[1827:58110] 2:视图已经排列子视图
2014-12-18 11:30:00.478 test[1827:58110] 2:视图已经出现
2014-12-18 11:30:00.478 test[1827:58110] 1:视图已经消失

视图控制器生命周期

2015-10-12 10:27:34.279 生命周期[7167:187683] viewDidLoad -- 1
2015-10-12 10:27:34.280 生命周期[7167:187683] viewWillAppear -- 1
2015-10-12 10:27:34.292 生命周期[7167:187683] viewDidAppear -- 1
2015-10-12 10:27:45.238 生命周期[7167:187683] viewDidLoad -- 2
2015-10-12 10:27:45.241 生命周期[7167:187683] viewWillDisappear -- 1
2015-10-12 10:27:45.242 生命周期[7167:187683] viewWillAppear -- 2
2015-10-12 10:27:45.753 生命周期[7167:187683] viewDidAppear -- 2
2015-10-12 10:27:45.754 生命周期[7167:187683] viewDidDisappear -- 1
2015-10-12 10:27:49.611 生命周期[7167:187683] viewWillDisappear -- 2
2015-10-12 10:27:49.611 生命周期[7167:187683] viewWillAppear -- 1
2015-10-12 10:27:50.115 生命周期[7167:187683] viewDidAppear -- 1
2015-10-12 10:27:50.115 生命周期[7167:187683] viewDidDisappear -- 2

四、事件机制

1、程序获取控件的两种方式

iOS应用提供了如下两种方式来获取程序控件:

  • ①、通过IBOutlet链接来获取控件;
  • ②、通过为空间指定tag属性,来获取该控件。

2、事件处理的方式

  • ①、通过IBAction绑定将控件的特定事件绑定到控制器的指定方式,当该控件上发生此事件时,将会出发控制器的对应方法;
  • ②、在程序中为UI控件的特定事件绑定事件监听器;
  • ③、对于UI控件的某些声明周期事件,可直接委托给对应的委托对象处理;

(1)、通过IBAction绑定实现事件处理
(2)、通过代码设置事件处理方法
iOS应用中能与用户交互的控件大都继承了UIControl基类,该类提供了如下方法来注册,删除事件处理方法:

  • ①、- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;为当前UIControl控件的制定事件注册事件处理方法。该方法需要指定如下三个参数:
addTarget:参数:该参数指定任意对象,表明将以该对象的方法作为事件处理方法。
action:参数:该参数接受一个SEL参数,代表一个IBAction方法,表明将以该IBAction方法作为事件处理方法。
forControlEvent:参数:该参数接受一个UIControlEvents类型的枚举值,该枚举值用于指定事件类型,表明为此种类型的事件绑定事件处理方法。
  • ②、- (void)removeTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;删除为当前UIControl控件的指定事件所注册的事件处理方法。

(3)、通过委托对象来处理事件

五、Storyboard的改进之处

六、代码控制UI界面

1、不适用界面布局文件开发UI界面

  • (1)、创建UI控件,比如创建UILabel、创建UIButton等。
  • (2)、调用addSubView:方法将UI控件添加到其他容器中。
  • (3)、多次调用UI控件的setter方法来设置UI控件的外观、行为。

2、使用代码创建UI界面

实例:动态添加、删除标签

  • ①、在RootViewController.h文件中
#import <UIKit/UIKit.h>
@interface RootViewController : UIViewController
//定义一个属性来记录所有动态添加的UILabel控件
@property (nonatomic ,strong) NSMutableArray* labels;
@end
  • ②、在RootViewController.m文件中
#import "RootViewController.h"
@interface RootViewController ()
@end
@implementation RootViewController
//定义一个变量来记录下一个将要添加的UILabel的位置
int nexty = 80;
- (void)viewDidLoad {
    [super viewDidLoad];
    //设置view的背景色
    self.view.backgroundColor = [UIColor grayColor];
    //初始化labels数组
    self.labels = [NSMutableArray array];
    //创建UIButtonTypeRoundedRect类型的UIButton对象
    UIButton* addBn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    //设置addBn的大小和位置
    addBn.frame = CGRectMake(30, 30, 60, 40);
    //为addBn设置按钮文本
    [addBn setTitle:@"添加" forState:UIControlStateNormal];
    //为addBn的Touch Up Inside事件绑定事件处理方法
    [addBn addTarget:self action:@selector(add:) forControlEvents:UIControlEventTouchUpInside];

    //创建UIButtonTypeRoundedRect类型的UIButton对象
    UIButton* removeBn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    //设置removeBn的大小和位置
    removeBn.frame = CGRectMake(230, 30, 60, 40);
    //为removeBn设置按钮文本
    [removeBn setTitle:@"删除" forState:UIControlStateNormal];
    //为removeBn的Touch Up Inside事件绑定事件处理方法
    [removeBn addTarget:self action:@selector(remove:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:addBn];
    [self.view addSubview:removeBn];
}
- (void)add:(UIButton *)sender{
    //创建一个UILabel控件
    UILabel* label = [[UILabel alloc]initWithFrame:CGRectMake(80, nexty, 160, 30)];
    label.text = @"疯狂iOS讲义";//设置该UILable显示的文本
    [self.labels addObject:label];//将该UILabel添加到labels数组中
    [self.view addSubview:label];//将UILabel控件添加到view父控件中
    nexty += 50;
}
- (void)remove:(UIButton *)sender{
    //如果labels数组中的元素个数大于0,表明UILabel可删除
    if (self.labels.count > 0) {
        //将最后一个UILabel从界面删除
        [[self.labels lastObject] removeFromSuperview];
        [self.labels removeLastObject];//从labels数组中删除最后一个元素
        nexty -= 50;//控制nexty的值减50
    }
}
@end
提示:CGRectMake()函数:CGRect结构体,他代表一个矩形区的大小和位置。CGRect结构体包括origin、size两个成员,其中origin又是CGPoint类型的一个结构体,它包括x、y两个成员,代表该矩形区左上角的位置;size又是CGSize类型的一个结构体,它包括width、height两个成员,代表该矩形区的宽度和高度。
    ①、CGRectMake()函数返回一个CGRect结构体;
    ②、CGPointMake(x,y)函数返回一个CGPoint结构体;
    ③、CGSizeMake(width,height)函数返回一个CGSize结构体。

3、自定义UI控件

UIView控件只是一个矩形的空白区域,并没有任何内容。iOS应用其他UI控件都继承了UIView,首先定义一个继承View基类的子类,然后重写View类的一个或多个方法,通常可以被用户重写的方法如下:

  • (1)、- (instancetype)initWithFrame:(CGRect)frame;程序创建UI控件时常常会调用该方法执行初始化;
  • (2)、- (instancetype)initWithCoder:(NSCoder *)aDecoder;程序通过在nib文件中加载完改控件后会自动调用该方法;
  • (3)、- (void)drawRect:(CGRect)rect;如果程序需要自行绘制该控件的内容,则可通过重写该方法来实现;
  • (4)、- (void)layoutSubviews;如果程序需要对该控件所包含的子控件布局进行更精确的控制,可通过重写该方法来实现;
  • (5)、- (void)didAddSubview:(UIView *)subview;当该控件添加子控件完成时,将会激发该方法;
  • (6)、- (void)willRemoveSubview:(UIView *)subview;当控件将要删除子控件时,将会激发该方法;
  • (7)、- (void)willMoveToSuperview:(UIView *)newSuperview;当该控件将要添加到其父控件中,将会激发该方法;
  • (8)、- (void)didMoveToSuperview;当该控件添加到父控件完成时,将会激发该方法;
  • (9)、- (void)willMoveToWindow:(UIWindow *)newWindow;当该控件将要添加到窗口中时,将会激发该方法;
  • (10)、- (void)didMoveToWindow;当把该控件添加到窗口完成时,将会激发该方法;
  • (11)、- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event;当用户手指开始触碰该控件时,将会激发该方法;
  • (12)、- (void)touchesMoved:(NSSet )touches withEvent:(UIEvent )event;当用户手指在该控件上移动时,将会激发该方法;
  • (13)、- (void)touchesEnded:(NSSet )touches withEvent:(UIEvent )event;当用户手机结束触碰该控件时,将会激发该方法;
  • (14)、- (void)touchesCancelled:(NSSet )touches withEvent:(UIEvent )event;用户取消触碰该控件时,将会激发该方法;

实例:跟随手指运动的小球:

#import "RootView.h"
int curX;
int curY;
@implementation RootView
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    //获取触碰事件的UITouch事件
    UITouch* touch = [touches anyObject];
    //得到触碰事件在当前组件上的触碰点
    CGPoint lastTouch = [touch locationInView:self];
    //获取触碰点的坐标
    curX = lastTouch.x;
    curY = lastTouch.y;
    //通知该组件重绘
    [self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect{
    //获取绘图上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //设置填充颜色
    CGContextSetFillColorWithColor(ctx, [UIColor yellowColor].CGColor);
    //以触碰点为圆心,绘制一个圆形
    CGContextFillEllipseInRect(ctx, CGRectMake(curX - 10, curY - 10, 20, 20));
}

七、美化iOS应用

如果点击模拟下的Home按键或按下command+Shift+H快捷键,模拟器返回应用程序列表。

1、定制iOS应用图标

  • (1)、准备四张作为应用程序图标的png格式的图片,这四张图片的大小分别为57像素*57像素、114像素*114像素、120像素*120像素、180像素*180像素。由于iPhone4引入了Retina显示屏幕,这种显示屏的分辨率是早期iPhone的两倍,因此需要分别制作两张图片,其中57像素*57像素的图标将适用于普通屏幕,114像素*114像素的图标将适用于Retina屏幕。而iPhone5s使用iOS7所用图标的大小为60像素*60像素,而且由于iPhone5s采用的是Retain屏幕(是普通屏幕的两倍),因此iOS7需要的图标为120像素*120像素。180像素*180像素应用于iOS8。
  • (2)、按下command+1组合键打开Xcode的项目导航面板,在该面板中展开要指定的图标的应用,然后选择该节点下的image.xcassets子节点。接下来选中项目导航面板右边的Dock区中的AppIcon节点,即可看到编辑界面。
  • (3)、然后把四张图片分别拖入图中,Xcode会将这四个文件复制到该应用中,并将这四张图片设为该应用的图标。注意:不要勾选iOS icon is pre-rendered复选框,这样系统会自动将该图标调整为圆角边框。

2、设置iOS应用的启动画面

定义iOS应用的步骤如下:

  1. 准备三张作为应用程序图标的png格式的图片,大小分别为320像素*480像素、640像素*960像素、640像素*1136像素。很明显,320像素*480像素的图片将适用于普通屏幕,而640像素*960像素适用于Retain屏幕。又由于iPhone5引入了更长的屏幕,其分辨率已达到640像素*1136像素像素。
  2. 按下command+1组合键打开Xcode的项目导航面板,在该面板中展开要启动画面的应用,然后选择该节点下的Image.xcassets子节点。接下来选中项目中导航面板右边的Dock区中的LaunchImage节点。可看到编辑界面:
  3. 从操作系统Finder中把三张图片分别拖入图中所示的5个图标处:320像素*480像素的图片拖入iOS5,6的1x图标框内、640像素*960像素的图片拖入iOS5,6的2x图标框内和R4内、640像素*1136像素的图片拖入iOS7,8的2x图标框和R4内。