UIKit简介
- 之前我们学习了如何在OS X平台(即Mac操作系统)编写应用程序。
- 接下来我们学习iOS平台编写应用程序。
- Mac应用程序使用的是AppKit框架,而iOS应用程序使用的是UIKit框架,它包含了所有的UI组件和构成iOS应用程序的资源。
iOS和OS X的不同
- iOS没有命令行使权,所以我们无法像在OS X上一样创建命令工具程序
- iOS没有shell和控制台
- iOS应用程序在Mac电脑的模拟器中运行
- iOS无法支持一些无UI界面的API
源代码及程序链接:https://pan.baidu.com/s/16g1nQ0WGW9LtEIMuvs-D3Q 密码:xkex
重新构建CaseTool
创建项目:
-
打开Xcode,选择iOS下的Single View App。
-
输入工程名称,并选择Next。
-
产生的界面
Single View Application图标,顾名思义就是这个程序只显示一个视图。这种类型的应用程序通常非常简单,用户界面也很简单。
其它模板的介绍
- Master-Detail应用程序:用一个导航控制器和一个表视图来显示项目列表以及项目的详细信息。
- Game:用来创建打发时间的绝妙游戏。
- Page-Based:创建一个类似书本的应用程序,它拥有翻页动画效果(只支持iPad)。
- Tabbed:用来创建多视图应用程序,就像你在iPhone上见到的底部有一个标签栏并且每个标签都与一个视图有关联的那种应用程序。
- Utility应用程序模板:拥有一个主视图,与Single View Application中的相似,但是还多出一个翻转视图。
- Empty应用程序是一个高级选项,如果没有合适的模板,或是你非常了解如何构建你的应用程序,那么可以选择使用这个模板。
代码介绍
//AppDelegate.h
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
//AppDelegate.m
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
// Override point for customization after application launch.
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
- 我们来看一下应用程序委托的头文件。首先是我们的老朋友#import,因为我们使用的是UIKit框架而不是AppKit框架,所以iOS界面元素都是以UI为前缀的。
- 我们还导入了Foundation框架,它在iOS平台上的工作原理与在OS X上的工作原理相似。因此,像NSString这样的类在iOS上是有效的,且使用方式与在OS X平台上相似。
- 实现文件的
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
系统默认提供了一个窗口对象和视图控制器。我们也可以在其中自定义。 - 如果你是自己定义的,那么你的自定义代码在窗口创建时便会调用,所有的应用程序都是在主窗口内运行的。接下来还要创建视图控制器。如果使用系统默认的,会有创建好的视图控制器文件。
视图控制器
- 之前说过,Cocoa主要使用的是MVC(Model-View-Controller)模式。确实,我们在应用程序拥有一个视图,一个控制器以及一组数据。
- 我们是从nib文件中获取视图的。这种方式非常便利,因为通过nib文件界面来设计和加载视图要比手动来做快得多。
- 我们的类ViewController是UIViewController的子类。UIViewController知道如何管理视图,比如将其放在屏幕上,调整大小,旋转,等等。如果想要管理视图的话,创建这个类的子类是非常有必要的。
- 那为什么不直接使用UIViewController类呢?因为我们需要向视图添加一些内容,而UIViewController并不知道有这些东西,所以我们需要创建它的子类并告诉子类如何处理我们新添加的内容。
在Nib文件中添加控件
- 打开Main.storyboard,你会看到以iPhone屏幕为尺寸显示的应用程序视图。你会看到,库对象面板中显示的内容都是针对iOS平台的
- 下面我们开始编辑nib文件。从右下角的对象面板中选择一个TextField对象并将其拖动到视图中。调整其大小以适应屏幕宽度,调整大小时可以参考引导线。
- 接下来,我们将一个label对象拖出并放入视图中,然后调整其大小。
- 下一步是添加一个按钮。在对象面板中选择Button图标,并将其拖动到视图中文本框和标签的下面。按钮完成以后,调整按钮大小使其能够匹配文本框的宽度。双击圆角按钮并给它命名,我们可以叫它UpperCase。
- 同样的,我们继续添加一个按钮,并将其放在第一个按钮的下方,调整其大小使它看上去与第一个按钮相似,并给它命名为LowerCase。
创建连接
- 在头文件的@interface和@end之间的位置放开鼠标,Xcode就会弹出这样的窗口。
- 窗口要求你填入输出口的名称。不过在这之前,请注意Object旁边的文字是File's Owner。这是什么意思呢?其实在你加载nib文件的时候,会有一个控制器作为它的拥有者。
- 当通过模板自动创建nib文件和控制器时,它会让控制器成为nib文件的拥有者。如果你需要的话,可以在nib文件中选择File's Owner图标并更改它的类。
1连接输出口(IBOutlet)
- Xcode窗口的右上角有三个标记为Editor的按钮,点击中间的按钮,就会将编辑器从中间垂直分成两部分,这就是辅助编辑器。
- 接下来,按住Control键并将光标拖动到头文件,出现“Insert Outlet or Action”提示消息再松手。松开鼠标会弹出如上图的一个对话框。
- 对话框第一项是选择Outlet还是Action,第二项是Name文本框,我们输入“textField”,并点击Connect按钮。这样做会在头文件中创建“textField”属性。
- 接下来对标签(label)重复之前的连接步骤并将其命名为“resultField”。
2连接操作(IBAction)
- 现在,我们将代码连接到操作,这样按下按钮就会触发代码
- 按住Control键并拖动鼠标到头文件,连接对话框会再次弹出。这次,要将连接类型改成Action。在Name文本框中输入UpperCase,并点击Connect按钮。
- 上面的操作将会在头文件中创建方法的声明,并会在.m文件中创建方法的实现(内容为空)。
- 现在,只要单击该按钮,UpperCase:消息就会如我们所想的那样发送给ViewController。我们可以在其中UpperCase执行任何想要的代码。
- 最后连接LowerCase按钮,按住Control键并拖动鼠标到头文件,将连接类型改成Action,连接名称设为“LowerCase”
Connection对话框中各项的信息
- Name(名称):该项包含了我们正在创建的操作的名称。
- Type(类型):操作方法参数的类名称。默认情况下这个值是id(泛型类),不过你可以将其改成发送消息给操作的任何类。在我们这个例子中,发送消息给操作的是一个UIButton类。
- Event(事件):在OS X和iOS平台之间有很大的不同,在iOS中有非常多的事件类型,都是由于触摸界面引起的。在这个例子中,我们打算使用Touch Up Inside事件。这意味着,当手指还在按钮上时停止屏幕触摸,便会调用按钮的操作方法
- Arguements(参数):在OS X应用程序中,没有Arguements选项,因为所有的操作都只有一个参数。在iOS环境下,我们有三种参数可以选择:None,Sender(OS X上的默认选项)和Event(包含一个UIEvent参数,你可以通过它来决定应该做什么)。我们将为操作选择None。
手动添加代码
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (nil != self) {
NSLog(@"init: text %@/ result %@",_textField,_resultsField);
}
return self;
}
- (void)awakeFromNib{
[super awakeFromNib];
NSLog(@"awake: text %@/ result %@",_textField,_resultsField);
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
这个方法是父类的方法,因此,我们不需要去实现它。我们调用这个代码以加载nib文件来访问输出口。- 视图控制器会在nib文件加载和对象初始化完成后调用viewDidLoad方法。一些较早版本的iOS系统还会调用awakeFromNib方法,不过在iOS 5中,已经不再调用了。
主要代码实现
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//更改背景
self.view.backgroundColor = [UIColor greenColor];
//初始化文本数据
[_textField setPlaceholder:@"Enter text here"];
_resultsField.text = @"Results";
}
- 我们将为viewDidLoad方法添加一些简单的实现。通常它们都是用来修改输出口和设置其它UI用的,当viewDidLoad方法调用了,你便能确定你的nib文件已经加完毕了。我们打算使用这个方法来设置一些文本框的默认值。
- 这段代码设定了textField文本框的占位符,它是在用户向文本框输入内容前显示的灰色文本。我们还要设置标签的默认值,以便用户知道这里将能看到转化后的结果。
- 在代码的后面,你将会看到viewDidLoad方法。视图从视图层级中移除后会调用这个方法。为什么要在意这些细节呢?为了保护内存不被泄露。
- iOS不支持虚拟内存。应用程序只能使用设备中可用的内存。此外如果使用了太多的内存,iOS将会强行退出应用程序以示抗议。我们通过viewDidLoad方法在事后清理内存。
- 在iOS(尤其是iPhone)应用程序中,大多数情况下,一个视图离开后另一个视图会来填满屏幕。这时,先前的那个视图便看不到了,因此就不需要再保留它了。
- iOS需要卸载视图来节约内存,所以viewDidLoad方法可以帮我们移除视图上的各项内容以节约一些内存,在这个示例中,我们移除了textField和resultsField控件。这两个方法(viewDidLoad和viewDidUnLoad)在视图的声明周期内只会调用到一次。
- 还有四个方法(viewWillAppear:、viewDidAppear:、viewWillDisAppear:、viewDidDisAppear:)也会在视图离开或出现的时候得到调用。每当条件合适的时候他们就会被调用,即便视图没有被卸载。
//实际执行大小写转化的代码
- (IBAction)uppercase:(id)sender {
//获取
NSString *original = _textField.text;
//改变
NSString *uppercase = [original uppercaseString];
//传递
_resultsField.text = uppercase;
}
- (IBAction)lowercase:(id)sender {
//获取
NSString *original = _textField.text;
//改变
NSString *lowercase = [original lowercaseString];
//传递
_resultsField.text = lowercase;
}
- 对于iOS的文本框,我们使用一个NSString方法来转换它的文本,将标签的文本值设置为修改后的字符串。就像在OS X上的那个应用一样,我们在这个例子中使用了stringValue和setStringValue:方法。