iOS开发系列--IOS程序开发概览
概览
终于到了真正接触IOS 应用程序的时刻了,之前我们花了很多时间去讨论C语言、ObjC等知识,对于很多朋友而言开发IOS第一天就想直接看到成果,看到可以运行的IOS程序。 但是这里我想强调一下,前面的知识是你日后开发IOS的基础,没有那些知识你开发IOS会很痛苦,现在很多开发人员做开发都是一知半解,程序质量确实令人 担忧,所以还是希望大家能够熟练掌握前面的内容,开发过程中多思考,彻底理解程序运行的原理、机制。好了言归正传,不管怎么样正式进入IOS开发还是令人 兴奋的,今天的内容虽然说是开发预览,其实还是有大量内容要说的:
- 第一个iOS程序
- iOS程序运行过程
- 文件结构
- Storyboard
- 纯代码实现iOS开发
- 补充知识点
第一个iOS程序
首 先打开Xcode—Create a new Xcode project—Single View Application--输入项目名称,同时选择使用Objective-C语言,设备选择iPhone--接下来系统默认生成一个IOS项目模板。项 目目录结构如下:
此时什么也不用做,直接运行看一下(注意这里已经切换模拟器为iPhone5),没错我们看到了一个iOS应用程序:
程序的运行过程
在几乎所有的程序开发中程序一般都是从main函数开始运行的,那么IOS程序也不例外,在上图中我们可以看到Xcode为我们生成了一个main.m文件:
// // main.m // FirstIOS // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
这个默认的iOS程序就是从main函数开始执行的,但是在main函数中我们其实只能看到一个方法,这个方法内部是一个消息循环(相当于一个死循 环),因此运行到这个方法UIApplicationMain之后程序不会自动退出,而只有当用户手动关闭程序这个循环才结束。这个方法有四个参数:
- 第一个参数和第二个参数其实就是main函数的参数,分别代表:参数个数、参数内容;
- 第三个参数代表UIApplication类(或子类)字符串,这个参数默认为nil则代表默认为UIApplication类,用户 可以自定义一个类继承于这个类;如果为nil则等价于NSStringFromClass([UIApplication class]),大家可以自己试验,效果完全一样;UIApplication是单例模式,一个应用程序只有一个UIApplication对象或子对 象;
- 第四个参数是UIApplication的代理类字符串,默认生成的是AppDelegate类,这个类主要用于监听整个应用程序生命 周期的各个事件(其实类似于之前我们文章中提到的事件监听代理),当UIApplication运行过程中引发了某个事件之后会调用代理中对应的方法;
小技巧:
其实在Xcode中如果要看一些系统方法的解释或者参数说明,可以直接鼠标放到这个方法上,在Xcode右侧面板中就会给出帮助提示,如下图当我们放到UIApplicationMain上之后:
也就是说当执行UIApplicationMain方法后这个方法会根据第三个参数创建对应的UIApplication对象,这个对象会根据第四 个参数AppDelegate创建并指定此对象为UIApplication的代理;同时UIApplication会开启一个消息循环不断监听应用程序 的各个活动,当应用程序生命周期发生改变UIApplication就会调用代理对应的方法。
既然应用程序UIApplication是通过代理和外部交互的,那么我们就有必要清楚AppDelegate的操作细节,下面是UIApplication详细的代码:
AppDelegate.h
// // AppDelegate.h // // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end
AppDelegate.m
// // AppDelegate.m // // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "AppDelegate.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 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 throttle down OpenGL ES frame rates. 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 inactive 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
这个类中定义了应用程序生命周期中各个事件的执行方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;程序启动之后执行,只有在第一次程序启动后才执行,以后不再执行;
- (void)applicationWillResignActive:(UIApplication *)application;程序将要失去焦点执行;
- (void)applicationDidEnterBackground:(UIApplication *)application;程序进入后台后执行,注意进入后台时,会先失去焦点,然后再进入后台;
- (void)applicationWillEnterForeground:(UIApplication *)application;程序将要进入前台时执行;
- (void)applicationDidBecomeActive:(UIApplication *)application;程序被激活(获得焦点)后执行,注意程序被激活时,会先进入前台,然后再被激活;
- (void)applicationWillTerminate:(UIApplication *)application;程序在终止时执行,包括正常终止或异常终止,例如说一个应用程序在后太运行(例如音乐播放软件、社交软件等)占用太多内存这时会意外终止调用此方法;
为了演示程序的生命周期,不妨在每个事件中都输出一段内容,简单调整上面的代码:
AppDelegate.m
// // AppDelegate.m // FirstIOS // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSLog(@"程序已经启动..."); return YES; } - (void)applicationWillResignActive:(UIApplication *)application { NSLog(@"程序将要失去焦点..."); // 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 throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { NSLog(@"程序已经进入后台..."); // 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 { NSLog(@"程序将要进入前台..."); // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { NSLog(@"程序已经获得焦点..."); // 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 { NSLog(@"程序将要终止..."); // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } -(void)applicationDidReceiveMemoryWarning:(UIApplication *)application{ } @end
下面是各个不同操作的运行结果:
相信通过上面运行过程大家会对整个运行周期有个大概了解。比较容易混淆的地方就是应用程序进入前台、激活、失去焦点、进入后台,这几个方法大家要清 楚。如果一个应用程序失去焦点那么意味着用户当前无法进行交互操作,因此一般会先失去焦点再进入后台防止进入后台过程中用户误操作;如果一个应用程序进入 前台也是类似的,会先进入前台再获得焦点,这样进入前台过程中未完全准备好的情况下用户无法操作。另外一般如果应用程序要保存用户数据会在注销激活中进行 (而不是在进入后台方法中进行),因为如果用户双击Home不会进入后台只会注销激活;如果用户恢复应用状态一般在进入激活状态时处理(而不是在进入前台 方法中进行),因为用户可能是从任务栏直接返回应用,此时不会执行进入前台操作。
当然,上面的事件并不是所有AppDelegate事件,而是最常用的一些事件,其他事件大家可以查阅官方文档,例如 -(void)applicationDidReceiveMemoryWarning:(UIApplication *)application;用于在内存占用过多发出内存警告时调用并通知对应的ViewController调用其内存回收方法。这里简单以图形方式描 述一下应用程序的调用过程:
文件结构
这里对于Xcode默认为我们生产的项目结果文件做一下简单介绍:
- AppDelegate(.h/.m):应用程序代理,主要用于监听整个应用程序生命周期中各个阶段的事件;
- ViewController(.h/.m):视图控制器,主要负责管理UIView的生命周期、负责UIView之间的切换、对UIView事件进行监听等;
- Main.storyboard:界面布局文件,承载对应UIView的视图控件;
- Images.xcassets:应用程序图像资源文件;
- Info.plist:应用程序配置文件;
- main.m:应用程序入口函数文件;
- xxx-prefix.pch:项目公共头文件,此文件中的导入语句在编译时会应用到所有的类文件中,相当于公共引入文件(注意在Xcode6中没有提供此文件)
Images.xcassets
关于AppDelegate、main.m前面已经介绍过了,ViewController和Main.storyboard在后面介绍,这里先说 一下Image.xcassets文件。在Xcode中打开这个文件会发现里面有两个设置项:AppIcon和LaunchImage
AppIcon
在AppIcon中可以看到三个图标设置,当我们勾选了右侧ios6.1 and Prior Sizes或者其他选项这个图标会自动增多,也就是说可以设计的图标跟应用程序准备支持的设备系统有关,这里我们就以默认的ios7为例(现在基本上设备都升级到ios7了):
a.iPhone Spotlight-iOS5,6 Settings-iOS 5-7 29pt:用于设置iOS5或者iOS6的搜索图标以及iOS5、iOS6、iOS7的设置图标,大小是58*58。
iOS搜索图标:
iOS设置图标:
b.iPhone Spootlight iOS 7 40pt:设置iOS7的搜索图标,大小是80*80。具体参见上图。
c.iPhone App iOS7 60pt:设置iOS7的应用图标,大小是120*120。
iOS应用图标:
LaunchImage
在LaunchImage中两个图标设计主要用于竖屏启动图
a.iPhone Portraint iOS7 2x:大小为640*1136的启动图片;
b.iPhone Portraint iOS7 R4:大小为640*960的启动图片;
其实上面的图片并不是所有图片都必须设置,具体要求可以直接查看苹果官方要求,例如这里我们设置应用图标和R4启动图片后具体效果如下(这里使用的图标取材来自微信):
上面我们添加了一个应用图标和一个启动图片,在Images.xcassets上右键在Fiddler中查看文件内容并进入 Images.xcassets文件夹,可以看到两个子文件夹:AppIcon.appiconset和 LaunchImage.launchimage,如下图:
两个文件夹中分别存放了我们前面设置的图片资源,除此之外还各有一个Contents.json文件,在这个文件中记录的资源信息,例如AppIcon.appiconset文件夹中的Contents.json内容如下,这里记录了每个图标的大小名称等信息:
Info.plist
Info.plist文件记录了应用程序的配置信息,如下图:
其实这些信息我们可以在项目属性中进行配置,效果和编辑这个文档是一样的,大家可以对照查看:
Storyboard
到目前为止我们还没有解释我们的程序是如何显示默认视图界面的。做过WinForm程序的朋友都知道每个Window窗口界面都有一个设计器(对应 一个设计文件),其实在IOS中也可以通过设计工具设计界面不用编写代码,这个工具就是Interface Builder。用Interface Builder编辑的文件在iOS5之前是一个“.xib”文件,从IOS5开始进行了改进,使用“.storyboard”文件进行设计。其实在上面我 们已经看到这个文件,这里重点说明一下Storyboard文件的使用。
首先我们打开Main.storyboard,此时可以看到一个Interface Builder界面设计器出现在我们眼前:
在这个界面中整个核心就是右侧视图控制器ViewController,在ViewController中有一个视图UIView,这个视图用来放 置其他用户操作控件。视图控制器左侧的箭头表示这个视图控制器是个主视图控制器,程序启动之后默认就会直接显示这个视图控制器的视图。我们可以在项目属性 中通过修改“Main Interface”属性来修改主视图控制器。
这里我们不妨从Xcode右侧工具栏Object Library中拖放一些组件在上面简单完成一个登录布局。
要实现这个登录,那么接下来就是事件和属性绑定的问题,大家应该可以猜到登录的逻辑代码肯定在ViewController.m中编写,那么 storyboard文件是如何关联到这个类的呢?如果我们在storyboard界面选中ViewController在Xcode右侧切换到 Identity Inspector视图就会发现里面当前设置的是ViewController类,通过这个设置Main.storyboard和 ViewController关联在一起。
那么如何在代码中读取两个TextField的值并通过点击按钮触发相关事件验证登录合法性呢?要想在代码中使用UITextField,并且添加按钮点击事件,则必须在ViewController.h中定义两个UITextField属性和一个登录方法。
上面代码我们需要解释一下IBOutlet、IBAction,其余代码和我们之前写的ObjC没有任何区别。
- IBOutlet:IBOutlet没有做任何操作,它的唯一作用就是告诉Interface Builder这个属性可以被关联到其中某个控件(在代码中可以看到代码前面多了空心圆点)。
- IBAction:其实就是void,只是当你定义为IBAction在Interface Builder中可以关联到某个控件的事件方法(后面的关联操作将会看到,而且我们在代码中也可以看到代码前面多了空心圆点);
下面看一下storyboard中的控件和代码中定义的属性和事件如何关联。Xcode为我们提供了几种方式来实现代码和storyboard控件的关联:
1.拖拽控件到代码中(首先点击Xcode右上方“Show the Assistant editor”切换对应视图,然后在代码中打开.h文件,同时打开Interface Builder,按住ctrl键拖拽控件到代码中相应的位置进行关联),关联后属性或方法前的空心圆变成实心表示已经关联到具体控件(注意:事实上,从控 件拖拽到代码时如果代码中没有定义对应的属性和方法Interface Builder会自动生成代码)。
2.从控件场景中拖拽控件到代码,关联后属性或方法前的空心圆变成实心表示已经关联到具体控件。(在Interface Builder中点击左下角“Show Document outline”显示控件结构树,选中相应的控件按住Ctrl键拖拽到代码中的属性或方法上)
3. 在控件上右键找到对应的属性或方法关联到代码中对应的属性或方法即可,关联后属性或方法前的空心圆变成实心表示已经关联到具体控件。
4.与方法3类似,不再截图,只是通过View Control Scene中的控件右键来关联,关联后属性或方法前的空心圆变成实心表示已经关联到具体控件。(在Interface Builder中点击左下角Show Document outline显示控件结构树,选中相应的控件右键拖拽到代码中的属性或方法上)
5.对于前面几种方法其实我们还可以直接从代码拖拽到控件上面,这里简单演示一种,其他情况大家可以自己试验。
如果要删除关联,可以采用第三、第四种方式在控件上右键,在关联菜单中找到对应的关联删除即可。此外需要注意对于一个控件而言可能有多个事件,当我 们使用第三种或第四种方式直接选择具体某个事件关联到login:方法自然没有问题,但是第一、第二、第五种方式没有提示我们关联到哪个事件而是使用一个 控件的默认事件(对于UIButton就是Touch Up Inside事件)。
既然控件和代码属性或方法已经做了关联,这里我们看一下具体效果,这里简单修改一下ViewController.m
// // ViewController.m // FirstIOS // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(void)login:(UIButton *)btn{ if ([_phoneNumber.text isEqual:@"123"]&&[_password.text isEqual:@"456"]) { NSLog(@"登录成功!"); } } @end
这里实现了login:方法模拟登录的过程,可以发现当在手机号码中输入“123”,在密码中输入“456”点击登录会输出”登录成功!“。
纯代码实现iOS开发
storyboard进行界面设计固然不错,特别是对于初学者经常会使用设计器进行界面设计,但是实际开发过程中我们很多情况下会直接使用代码进行界面布局,特别是对于复杂的界面布局更是如此。下面我们就从一个空项目建立一个类似于前面的登录界面。
直接在Xcode中创建“Empty Application”(注意在Xcode6中这个选项已经没有了,这里采用Xcode5.1),此时会发现已经没有ViewController和 storyboard文件,我们需要手动创建一个视图控制器(在项目中右键选择Objective-c class,默认继承自UIViewController,输入类名:KCMainViewController即可)。
新建的视图控制器默认情况下是无法加载到程序运行界面上的,此时需要在应用程序代理的程序加载完毕事件中手动加载并显示我们的视图。修改之前KCAppDelegate.m代码如下:
// KCAppDelegate.m // IOSByCode // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCAppDelegate.h" @implementation KCAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; 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 throttle down OpenGL ES frame rates. 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 inactive 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
我们修改上面- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions的代码如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //设置window属性(在KCAppDelegate中定义的window属性),初始化windows的大小和位置 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. //设置window的背景 self.window.backgroundColor = [UIColor whiteColor]; //初始化KCMainViewController KCMainViewController *mainController=[[KCMainViewController alloc]init]; //设置自定义控制器的大小和window相同,位置为(0,0) mainController.view.frame=self.window.bounds; //设置此控制器为window的根控制器 self.window.rootViewController=mainController; //设置window为应用程序主窗口并设为可见 [self.window makeKeyAndVisible]; return YES; }
然后在我们自定义的KCMainViewController.m中添加一个UIImageView、两个控件UITextField和一个UIButton控件,并且实现具体的登录方法。
KCMainViewController.h
// // KCMainViewController.h // IOSByCode // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <UIKit/UIKit.h> @interface KCMainViewController : UIViewController #pragma mark logo @property (nonatomic,strong) UIImageView *logo; #pragma mark 手机号码 @property (nonatomic,strong) UITextField *phoneNumber; #pragma mark 密码 @property (nonatomic,strong) UITextField *password; #pragma mark 登录按钮 @property (nonatomic,strong) UIButton *loginButton; #pragma mark 点击事件 -(void)login:(UIButton *)btn; @end
KCMainViewController.m
// // KCMainViewController.m // IOSByCode // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController () @end @implementation KCMainViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Custom initialization } return self; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. //self.view.backgroundColor=[UIColor redColor]; //添加图片 CGRect logoRect=CGRectMake(100, 50, 100, 200); _logo=[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"LoginBackground.png"]];//设置图片 _logo.contentMode=UIViewContentModeScaleAspectFit;//设置内容填充模式 _logo.frame=logoRect;//设置控件大小和位置(相对于父控件的位置) [self.view addSubview:_logo];//添加到KCMainViewController的View中 //添加手机号码输入框 CGRect phoneNumberRect=CGRectMake(20, 320, 280, 30); _phoneNumber=[[UITextField alloc]initWithFrame:phoneNumberRect]; _phoneNumber.borderStyle=UITextBorderStyleRoundedRect;//设置文本框的边框样式 [self.view addSubview:_phoneNumber]; //添加密码输入框 CGRect passwordRect=CGRectMake(20, 380, 280, 30); _password=[[UITextField alloc]initWithFrame:passwordRect]; _password.borderStyle=UITextBorderStyleRoundedRect; [self.view addSubview:_password]; //添加登录按钮 CGRect loginButtonRect=CGRectMake(10, 440, 300, 25); _loginButton=[[UIButton alloc]initWithFrame:loginButtonRect]; [_loginButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];//设置标题内容颜色 [_loginButton setTitle:@"登录" forState:UIControlStateNormal];//设置按钮标题 [_loginButton addTarget:self action:@selector(login:) forControlEvents:UIControlEventTouchUpInside];//添加点击事件 [self.view addSubview:_loginButton]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } -(void)login:(UIButton *)btn{ if ([_phoneNumber.text isEqual:@"123"]&&[_password.text isEqual:@"456"]) { NSLog(@"登录成功!"); }else{ NSLog(@"登录失败!"); } } @end
运行效果如下,与之前使用storyboard创建的界面类似,同时也能点击登录:
UIView
在这里我们需要对上面的代码一样解释,在弄清上面的代码之前我们不得不熟悉一个UIKit中最重要的类UIView。
- UIView就是指界面可见的控件元素,所有的控件最终都继承自UIView,UIView中还可以添加其他UIView(通过addSubView方法);
- 在一个iOS应用中必须有一个主窗口UIWindow(理论上也可以有多个UIWindow但是只有一个是主Window,而且只有主Window可以和用户交互),UIWindow也是继承自UIView,它拥有UIView的所有属性、方法;
- 在UIWindow中必须有一个根控制器,这个控制器距离UIWindow是最近的;设置一个控制器为根控制器和直接通过 addSubView添加控制器的视图(view属性)到window并不完全一样(例如如果仅仅添加控制器视图那么应用虽然可以显示但是不支持旋转);
- UIViewController是视图控制器,主要用来控制UIView,在UIViewController内部有一个UIView(view属性);
在上面的代码中我们首先在应用程序加载完毕之后加载一个UIWindow对象,同时把我们的视图控制器KCMainController设置为 UIWindow的根视图控制器,然后设置这个UIWindow为主窗口并可见。当主窗口设置为可见过程中会调用视图控制器的loadView方法来加载 视图(注意视图控制器的loadView方法是延迟加载的,第一次调用视图控制器的view属性才会调用此方法;由于makeKeyAndVisible 方法中会使用视图控制器的view属性所以此时会调用视图控制器的loadView方法),视图加载完之后调用viewDidLoad方法,在这个方法中 我们添加登录相关控件并将这些控件加载到视图控制器KCMainViewController的视图view中。
下面我们看一下应用程序最终的布局,相信通过这张图大家对于iOS的布局会有一个大致了解:
补充知识点
1.iOS尺寸设置--在iOS中尺寸的单位是点不是像素,在retina屏幕中一个点有两个像素。此外在retina屏幕中图片一般采用”xxx@2x.png”命名,在代码中使用时只需要写成“xxx.png”程序会自动根据屏幕类型在retain屏幕下使用”xxx@2x.png”图片,在非retain屏幕下采用”xxx.png”图片。
2.应用程序图像资源尺寸--其实关于图片尺寸规定我们可以直接查看Xcode自带帮助文档,例如可以查看“Icon and Image Sizes”一节获得图片大小说明:
关于iOS图标命名这里不再赘述,苹果官方也给出了具体的代码示例:Application Icons and Launch Images for iOS
3.模拟器文件存储的位置--模拟器中为什么可以运行我们的程序,程序到底在什么位置?
这些文件其实在Mac中 OS X中是隐藏的,首先通过“defaults write com.apple.finder AppleShowAllFiles -bool true” 命令显示隐藏文件(关闭隐藏文件显示通过“defaults write com.apple.finder AppleShowAllFiles -bool false”命令),然后到“/Users/kenshincui/Library/Application Support/iPhone Simulator/7.1/Applications”文件夹中会看到很多GUID命名的文件夹,只要一个一个查看就可以找到我们的程序。模拟器运行时 会加载这个文件夹中的应用程序包显示到模拟器中。
可以看到在上图中有一个IOSByCode的应用程序包,我们可以通过“显示包内容”查看具体程序资源:
4.UIApplication--前面一直提到UIApplication对象,这个对象在iOS中是一个单例,我们通过 [UIApplication sharedApplication]获得(注意在iOS开发中一般以shared开头的对象都是单例)。这里列举一些UIApplication的常用 方法:
例如调用applicationIconBadgeNumber方法之后效果如下:
5.组织标示--前面我们在新建项目中有一个“Organization Identifier”是做什么的呢?它是组织唯一标示,一般我们会使用公司的域名形式(这个域名一般会倒序书写,例如公司域名为:www.cmjstudio.com,我们这里就写成com.cmjstudio),和项目名称共同组成一个程序的唯一标示“Bundle Identifier”,这个标示在整个App Store中是唯一的,如果两个应用程序标示完全一样,那么安装时会先卸载前面的程序再安装新程序。
![]() |
本作品采用知识共享署名 2.5 中国大陆许可协议进行许可,欢迎转载,演绎或用于商业目的。但转载请注明来自崔江涛(KenshinCui),并包含相关链接。 |
相关推荐
全国大学生智能汽车竞赛自2006年起,由教育部高等教育司委托高等学校自动化类教学指导委员会举办,旨在加强学生实践、创新能力和培养团队精神的一项创意性科技竞赛。该竞赛至今已成功举办多届,吸引了众多高校学生的积极参与,此文件为智能车竞赛介绍
字卡v4.3.4 原版 三种UI+关键字卡控制+支持获取用户信息+支持强制关注 集卡模块从一开始的版本到助力版本再到现在的新规则版本。 集卡模块难度主要在于 如何控制各种不同的字卡组合 被粉丝集齐的数量。 如果不控制那么一定会出现超过数量的粉丝集到指定的字卡组合,造成奖品不够的混乱,如果大奖价值高的话,超过数量的粉丝集到大奖后,就造成商家的活动费用超支了。我们冥思苦想如何才能限制集到指定字卡组合的粉丝数,后我们想到了和支付宝一样的选一张关键字卡来进行规则设置的方式来进行限制,根据奖品所需的关键字卡数,设定规则就可以控制每种奖品所需字卡组合被粉丝集到的数量,规则可以在活动进行中根据需要进行修改,活动规则灵活度高。新版的集卡规则,在此次政府发布号的活动中经受了考验,集到指定字卡组合的粉丝没有超出规则限制。有了这个规则限制后,您无需盯着活动,建好活动后就无人值守让活动进行就行了,您只需要时不时来看下蹭蹭上涨的活动数据即可。 被封? 无需担心,模块内置有防封功能,支持隐藏主域名,显示炮灰域名,保护活动安全进行。 活动准备? 只需要您有一个认证服务号即可,支持订阅号借用认证服务号来做活动。如果您
出口设备线体程序详解:PLC通讯下的V90控制与开源FB284工艺对象实战指南,出口设备线体程序详解:PLC通讯与V90控制集成,工艺对象与FB284协同工作,开源学习V90控制技能,出口设备1200线体程序,多个plc走通讯,内部有多个v90,采用工艺对象与fb284 共同控制,功能快全部开源,能快速学会v90的控制 ,出口设备; 1200线体程序; PLC通讯; 多个V90; 工艺对象; FB284; 功能开源; V90控制。,V90工艺控制:开源功能快,快速掌握1200线体程序与PLC通讯
基于Arduino与DAC8031的心电信号模拟器资料:心电信号与正弦波的双重输出应用方案,Arduino与DAC8031心电信号模拟器:生成心电信号与正弦波输出功能详解,基于arduino +DAC8031的心电信号模拟器资料,可输出心电信号,和正弦波 ,基于Arduino;DAC8031;心电信号模拟器;输出心电信号;正弦波输出;模拟器资料,基于Arduino与DAC8031的心电信号模拟器:输出心电与正弦波
MATLAB口罩检测的基本流程 图像采集:通过摄像头或其他图像采集设备获取包含面部的图像。 图像预处理:对采集到的图像进行灰度化、去噪、直方图均衡化等预处理操作,以提高图像质量,便于后续的人脸检测和口罩检测。 人脸检测:利用Haar特征、LBP特征等经典方法或深度学习模型(如MTCNN、FaceBoxes等)在预处理后的图像中定位人脸区域。 口罩检测:在检测到的人脸区域内,进一步分析是否佩戴口罩。这可以通过检测口罩的边缘、纹理等特征,或使用已经训练好的口罩检测模型来实现。 结果输出:将检测结果以可视化方式展示,如在图像上标注人脸和口罩区域,或输出文字提示是否佩戴口罩。
1、文件内容:kernel-debug-devel-3.10.0-1160.119.1.el7.rpm以及相关依赖 2、文件形式:tar.gz压缩包 3、安装指令: #Step1、解压 tar -zxvf /mnt/data/output/kernel-debug-devel-3.10.0-1160.119.1.el7.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm 4、更多资源/技术支持:公众号禅静编程坊
该文档提供了一个关于供应链管理系统开发的详细指南,重点介绍了项目安排、技术实现和框架搭建的相关内容。 文档分为以下几个关键部分: 项目安排:主要步骤包括搭建框架(1天),基础数据模块和权限管理(4天),以及应收应付和销售管理(5天)。 供应链概念:供应链系统的核心流程是通过采购商品放入仓库,并在销售时从仓库提取商品,涉及三个主要订单:采购订单、销售订单和调拨订单。 大数据的应用:介绍了数据挖掘、ETL(数据抽取)和BI(商业智能)在供应链管理中的应用。 技术实现:讲述了DAO(数据访问对象)的重用、服务层的重用、以及前端JS的继承机制、jQuery插件开发等技术细节。 系统框架搭建:包括Maven环境的配置、Web工程的创建、持久化类和映射文件的编写,以及Spring配置文件的实现。 DAO的需求和功能:供应链管理系统的各个模块都涉及分页查询、条件查询、删除、增加、修改操作等需求。 泛型的应用:通过示例说明了在Java语言中如何使用泛型来实现模块化和可扩展性。 文档非常技术导向,适合开发人员参考,用于构建供应链管理系统的架构和功能模块。
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
C#与VB实现欧姆龙PLC的Fins TCP通信案例源码:调用动态链接库进行数据读写,定时器与计数器数据区的简洁读写操作示例,C#与VB实现欧姆龙PLC的Fins TCP通信案例源码:调用动态链接库进行读写操作,涵盖定时器计数器数据区学习案例,C#欧姆龙plc Fins Tcp通信案例上位机源码,有c#和VB的Demo,c#上位机和欧姆龙plc通讯案例源码,调用动态链接库,可以实现上位机的数据连接,可以简单实现D区W区定时器计数器等数据区的读写,是一个非常好的学习案例 ,C#; 欧姆龙PLC; Fins Tcp通信; 上位机源码; 动态链接库; 数据连接; D区W区读写; 定时器计数器; 学习案例,C#实现欧姆龙PLC Fins Tcp通信上位机源码,读写数据区高效学习案例
可调谐石墨烯超材料吸收体的FDTD仿真模拟研究报告:吸收光谱的化学势调节策略与仿真源文件解析,可调谐石墨烯超材料吸收体:化学势调节光谱的FDTD仿真模拟研究,可调谐石墨烯超材料吸收体FDTD仿真模拟 【案例内容】该案例提供了一种可调谐石墨烯超材料吸收体,其吸收光谱可以通过改变施加于石墨烯的化学势来进行调节。 【案例文件】仿真源文件 ,可调谐石墨烯超材料吸收体; FDTD仿真模拟; 化学势调节; 仿真源文件,石墨烯超材料吸收体:FDTD仿真调节吸收光谱案例解析
RBF神经网络控制仿真-第二版
松下PLC与威纶通触摸屏转盘设备控制:FPWINPRO7与EBPRO智能编程与宏指令应用,松下PLC与威纶通触摸屏转盘设备控制解决方案:FPWINPRO7与EBPRO协同工作,实现多工位转盘加工与IEC编程模式控制,松下PLC+威纶通触摸屏的转盘设备 松下PLC工程使用程序版本为FPWINPRO7 7.6.0.0版本 威纶通HMI工程使用程序版本为EBPRO 6.07.02.410S 1.多工位转盘加工控制。 2.国际标准IEC编程模式。 3.触摸屏宏指令应用控制。 ,松下PLC; 威纶通触摸屏; 转盘设备控制; 多工位加工控制; IEC编程模式; 触摸屏宏指令应用,松下PLC与威纶通HMI联控的转盘设备控制程序解析
基于循环神经网络(RNN)的多输入单输出预测模型(适用于时间序列预测与回归分析,需Matlab 2021及以上版本),基于循环神经网络(RNN)的多输入单输出预测模型(matlab版本2021+),真实值与预测值对比,多种评价指标与线性拟合展示。,RNN预测模型做多输入单输出预测模型,直接替数据就可以用。 程序语言是matlab,需求最低版本为2021及以上。 程序可以出真实值和预测值对比图,线性拟合图,可打印多种评价指标。 PS:以下效果图为测试数据的效果图,主要目的是为了显示程序运行可以出的结果图,具体预测效果以个人的具体数据为准。 2.由于每个人的数据都是独一无二的,因此无法做到可以任何人的数据直接替就可以得到自己满意的效果。 这段程序主要是一个基于循环神经网络(RNN)的预测模型。它的应用领域可以是时间序列预测、回归分析等。下面我将对程序的运行过程进行详细解释和分析。 首先,程序开始时清空环境变量、关闭图窗、清空变量和命令行。然后,通过xlsread函数导入数据,其中'数据的输入'和'数据的输出'是两个Excel文件的文件名。 接下来,程序对数据进行归一化处理。首先使用ma
1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。
旅游管理系统中的功能模块主要是实现管理员;首页、个人中心、用户管理、旅游方案管理、旅游购买管理、系统管理,用户;首页、个人中心、旅游方案管理、旅游购买管理、我的收藏管理。前台首页;首页、旅游方案、旅游资讯、个人中心、后台管理等功能。经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与旅游管理系统实现的实际需求相结合,讨论了Java开发旅游管理系统的使用。 从上面的描述中可以基本可以实现软件的功能: 1、开发实现旅游管理系统的整个系统程序; 2、管理员;首页、个人中心、用户管理、旅游方案管理、旅游购买管理、系统管理等。 3、用户:首页、个人中心、旅游方案管理、旅游购买管理、我的收藏管理。 4、前台首页:首页、旅游方案、旅游资讯、个人中心、后台管理等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流查看及回复相应操作。
Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基于功率反馈的扰动观察法调整电压方向研究,Boost二级升压光伏并网结构的Simulink建模与MPPT最大功率点追踪:基于功率反馈的扰动观察法调整电压方向研究,Boost二级升压光伏并网结构,Simulink建模,MPPT最大功率点追踪,扰动观察法采用功率反馈方式,若ΔP>0,说明电压调整的方向正确,可以继续按原方向进行“干扰”;若ΔP<0,说明电压调整的方向错误,需要对“干扰”的方向进行改变。 ,Boost升压;光伏并网结构;Simulink建模;MPPT最大功率点追踪;扰动观察法;功率反馈;电压调整方向。,光伏并网结构中Boost升压MPPT控制策略的Simulink建模与功率反馈扰动观察法
运行GUI版本,可二开
Deepseek相关主题资源及行业影响
WP Smush Pro 是一款专为 WordPress 网站设计的图像优化插件。 一、主要作用 图像压缩 它能够在不影响图像质量的前提下,大幅度减小图像文件的大小。例如,对于一些高分辨率的产品图片或者风景照片,它可以通过先进的压缩算法,去除图像中多余的数据。通常 JPEG 格式的图像经过压缩后,文件大小可以减少 40% – 70% 左右。这对于网站性能优化非常关键,因为较小的图像文件可以加快网站的加载速度。 该插件支持多种图像格式的压缩,包括 JPEG、PNG 和 GIF。对于 PNG 图像,它可以在保留透明度等关键特性的同时,有效地减小文件尺寸。对于 GIF 图像,也能在一定程度上优化文件大小,减少动画 GIF 的加载时间。 懒加载 WP Smush Pro 实现了图像懒加载功能。懒加载是一种延迟加载图像的技术,当用户滚动页面到包含图像的位置时,图像才会加载。这样可以避免一次性加载大量图像,尤其是在页面内容较多且包含许多图像的情况下。例如,在一个新闻网站的长文章页面,带有大量配图,懒加载可以让用户在浏览文章开头部分时,不需要等待所有图片加载,从而提高页面的初始加载速度,同时也能
Could not create share link. Missing file: C:\Users\xx\.conda\envs\omni\Lib\site-packages\gradio\frpc_windows_amd64_v0.3 1. Download this file: https://cdn-media.huggingface.co/frpc-gradio-0.3/frpc_windows_amd64.exe 2. Rename the downloaded file to: frpc_windows_amd64_v0.3 3. Move the file to this location: C:\Users\xx\.conda\envs\omni\Lib\site-packages\gradio