一个java程序员自学IOS开发之路(七)java
2015/11/2ios
Day 30程序员
今天学习UIPickerView,UIDatePicker编程
他们的使用方法与UITableView及其相似,实现数据源方法,代理方法就能显示数据windows
一.UIPickerViewxcode
1.UIPickerView的常见属性缓存
// 数据源(用来告诉UIPickerView有多少列多少行)app
@property(nonatomic,assign) id<UIPickerViewDataSource> dataSource;ide
// 代理(用来告诉UIPickerView每1列的每1行显示什么内容,监听UIPickerView的选择)函数
@property(nonatomic,assign) id<UIPickerViewDelegate> delegate;
// 是否要显示选中的指示器
@property(nonatomic) BOOL showsSelectionIndicator;
// 一共有多少列
@property(nonatomic,readonly) NSInteger numberOfComponents;
2.UIPickerView的常见方法
// 从新刷新全部列
- (void)reloadAllComponents;
// 从新刷新第component列
- (void)reloadComponent:(NSInteger)component;
// 主动选中第component列的第row行
- (void)selectRow:(NSInteger)row inComponent:(NSInteger)component animated:(BOOL)animated;
// 得到第component列的当前选中的行号
- (NSInteger)selectedRowInComponent:(NSInteger)component;
3.数据源方法(UIPickerViewDataSource)
// 一共有多少列
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
// 第component列一共有多少行
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
4.代理方法(UIPickerViewDelegate)
// 第component列的宽度是多少
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component;
// 第component列的行高是多少
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component;
// 第component列第row行显示什么文字
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
// 第component列第row行显示怎样的view(内容)
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view;
// 选中了pickerView的第component列第row行
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
二.UIDatePicker
1.常见属性
// datePicker的显示模式
@property (nonatomic) UIDatePickerMode datePickerMode;
// 显示的区域语言
@property (nonatomic, retain) NSLocale *locale;
2.监听UIDatePicker的选择
* 由于UIDatePicker继承自UIControl,因此经过addTarget:...监听
2015/11/3
Day 31
今天学习程序启动原理
常见属性
◆ Localiztion native development region(CFBundleDevelopmentRegion)-本地化相关
◆ Bundle display name(CFBundleDisplayName)-程序安装后显示的名称,限制在10-12个字符,若是超出,将被显示缩写名称
◆ Icon file(CFBundleIconFile)-app图标名称,通常为Icon.png
◆ Bundle version(CFBundleVersion)-应用程序的版本号,每次往App Store上发布一个新版本时,须要增长这个版本号
◆ Main storyboard file base name(NSMainStoryboardFile)-主storyboard文件的名称
◆ Bundle identifier(CFBundleIdentifier)-项目的惟一标识,部署到真机时用到
在Xcode6以前,建立一个新工程xcode会在Supporting files文件夹下面自动建立一个“工程名-Prefix.pch”文件,也是一个头文件,pch头文件的内容能被项目中的其余全部源文件共享和访问。是一个预编译文件。
首先说一下pch的做用:
1.存放一些全局的宏(整个项目中都用得上的宏)
2.用来包含一些所有的头文件(整个项目中都用得上的头文件)
3.能自动打开或者关闭日志输出功能
Xcode6之后就不能自动建立了,苹果为何要这么作呢,缘由多是由于你们把大量的头文件和宏定义放到pch里边,致使编译时间过长。苹果去掉他多是要加快编译时间增长用户体验。虽然失去了编程的便利性。不得不佩服苹果的以用户为中心的思考方式
UIApplication
UIApplication对象是应用程序的象征
每个应用都有本身的UIApplication对象,并且是单例的
经过[UIApplication sharedApplication]能够得到这个单例对象
一个iOS程序启动后建立的第一个对象就是UIApplication对象
利用UIApplication对象,能进行一些应用级别的操做
@property(nonatomic) NSInteger applicationIconBadgeNumber;
@property(nonatomic,getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
从iOS7开始,系统提供了2种管理状态栏的方式
- (UIStatusBarStyle)preferredStatusBarStyle;
- (BOOL)prefersStatusBarHidden;
UIApplication有个功能十分强大的openURL:方法
- (BOOL)openURL:(NSURL*)url;
openURL:方法的部分功能有
UIApplication *app = [UIApplication sharedApplication];
[app openURL:[NSURL URLWithString:@"tel://10086"]];
[app openURL:[NSURL URLWithString:@"sms://10086"]];
[app openURL:[NSURL URLWithString:@"mailto://12345@qq.com"]];
[app openURL:[NSURL URLWithString:@"http://ios.itcast.cn"]];
全部的移动操做系统都有个致命的缺点:app很容易受到打扰。好比一个来电或者锁屏会致使app进入后台甚至被终止
还有不少其它相似的状况会致使app受到干扰,在app受到干扰时,会产生一些系统事件,这时UIApplication会通知它的delegate对象,让delegate代理来处理这些系统事件
delegate可处理的事件包括:
➢ 应用程序的生命周期事件(如程序启动和关闭)
➢ 系统事件(如来电)
➢ 内存警告
➢ … …
IOS程序启动过程
UIApplicationMain
main函数中执行了一个UIApplicationMain这个函数
int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
➢ argc、argv:直接传递给UIApplicationMain进行相关处理便可
➢ principalClassName:指定应用程序类名(app的象征),该类必须是UIApplication(或子类)。若是为nil,则用UIApplication类做为默认值
➢ delegateClassName:指定应用程序的代理类,该类必须遵照UIApplicationDelegate协议
UIApplicationMain函数会根据principalClassName建立UIApplication对象,根据delegateClassName建立一个delegate对象,并将该delegate对象赋值给UIApplication对象中的delegate属性
接着会创建应用程序的Main Runloop(事件循环),进行事件的处理(首先会在程序完毕后调用delegate对象的application:didFinishLaunchingWithOptions:方法)
程序正常退出时UIApplicationMain函数才返回
UIWindow
UIWindow是一种特殊的UIView,一般在一个app中只会有一个UIWindow
iOS程序启动完毕后,建立的第一个视图控件就是UIWindow,接着建立控制器的view,最后将控制器的view添加到UIWindow上,因而控制器的view就显示在屏幕上了
一个iOS程序之因此能显示到屏幕上,彻底是由于它有UIWindow
也就说,没有UIWindow,就看不见任何UI界面
添加UIView到UIWindow中两种常见方式:
直接将view添加到UIWindow中,但并不会理会view对应的UIViewController
自动将rootViewController的view添加到UIWindow中,负责管理rootViewController的生命周期
经常使用方法
让当前UIWindow变成keyWindow(主窗口)
让当前UIWindow变成keyWindow,并显示出来
UIWindow的得到
在本应用中打开的UIWindow列表,这样就能够接触应用中的任何一个UIView对象
(平时输入文字弹出的键盘,就处在一个新的UIWindow中)
用来接收键盘以及非触摸类的消息事件的UIWindow,并且程序中每一个时刻只能有一个UIWindow是keyWindow。若是某个UIWindow内部的文本框不能输入文字,多是由于这个UIWindow不是keyWindow
得到某个UIView所在的UIWindow
四大对象的关系
程序启动的完整过程
1.main函数
2.UIApplicationMain
* 建立UIApplication对象
* 建立UIApplication的delegate对象
3.delegate对象开始处理(监听)系统事件(没有storyboard)
* 程序启动完毕的时候, 就会调用代理的application:didFinishLaunchingWithOptions:方法
* 在application:didFinishLaunchingWithOptions:中建立UIWindow
* 建立和设置UIWindow的rootViewController
* 显示窗口
3.根据Info.plist得到最主要storyboard的文件名,加载最主要的storyboard(有storyboard)
* 建立UIWindow
* 建立和设置UIWindow的rootViewController
* 显示窗口
2015/11/4
Day 32
今天开始学习多控制器
控制器常见的建立方式有如下几种
ViewController *vc = [[ViewController alloc] init];
ViewController *vc = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
经过storyboard建立控制器
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Test" bundle:nil];
初始化“初始控制器”(箭头所指的控制器)
MJViewController *mj = [storyboard instantiateInitialViewController];
MJViewController *mj = [storyboard instantiateViewControllerWithIdentifier:@”mj"];
控制器view的建立
❖ 控制器的view是延迟加载的:用到时再加载
❖ 能够用isViewLoaded方法判断一个UIViewController的view是否已经被加载
❖ 控制器的view加载完毕就会调用viewDidLoad方法
一个iOS的app不多只由一个控制器组成,除非这个app极其简单
当app中有多个控制器的时候,咱们就须要对这些控制器进行管理
有多个view时,能够用一个大的view去管理1个或者多个小view
控制器也是如此,用1个控制器去管理其余多个控制器
好比,用一个控制器A去管理3个控制器B、C、D
➢ 控制器A被称为控制器B、C、D的“父控制器”
➢ 控制器B、C、D的被称为控制器A的“子控制器”
➢
为了便于管理控制器,iOS提供了2个比较特殊的控制器
➢ UINavigationController
➢ UITabBarController
❖ 利用UINavigationController,能够轻松地管理多个控制器,轻松完成控制器之间的切换,典型例子就是系统自带的“设置”应用
UINavigationController的使用步骤
初始化UINavigationController
设置UIWindow的rootViewController为UINavigationController
根据具体状况,经过push方法添加对应个数的子控制器
注意:xcode6 以后push 和modal 就被废弃了。只能用于ios8以前
这两个方法被废弃了,咱们须要找到合适的方法来代替,这时候咱们发现 show 和Present Modally 方法,这个通常能够知足使用要求。
@property(nonatomic,copy) NSArray *viewControllers;
@property(nonatomic,readonly) NSArray *childViewControllers;
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (UIViewController *)popViewControllerAnimated:(BOOL)animated;
- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated;
导航栏的内容由栈顶控制器的navigationItem属性决定
UINavigationItem有如下属性影响着导航栏的内容
@property(nonatomic,retain) UIBarButtonItem *backBarButtonItem;
@property(nonatomic,retain) UIView *titleView;
@property(nonatomic,copy) NSString *title;
@property(nonatomic,retain) UIBarButtonItem *leftBarButtonItem;
@property(nonatomic,retain) UIBarButtonItem *rightBarButtonItem;
数据存取
iOS应用数据存储的经常使用方式
● XML属性列表(plist)归档
● Preference(偏好设置)
● NSKeyedArchiver归档(NSCoding)
● SQLite
● Core Data
应用沙盒
● 每一个iOS应用都有本身的应用沙盒(应用沙盒就是文件系统目录),与其余文件系统隔离。应用必须待在本身的沙盒里,其余应用不能访问该沙盒
● 应用沙盒的文件系统目录,以下图所示(假设应用的名称叫Layer)
● 应用程序包:(上图中的Layer)包含了全部的资源文件和可执行文件
● Documents:保存应用运行时生成的须要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录
●
● tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录
●
● Library/Caches:保存应用运行时生成的须要持久化的数据,iTunes同步设备时不会备份该目录。通常存储体积大、不须要备份的非重要数据
●
● Library/Preference:保存应用的全部偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录
应用沙盒目录的常见获取方式
NSString *home = NSHomeDirectory();
NSString *documents = [home stringByAppendingPathComponent:@"Documents"];
// 不建议采用,由于新版本的操做系统可能会修改目录名
// NSUserDomainMask 表明从用户文件夹下找
// YES 表明展开路径中的波浪字符“~”
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, NO);
// 在iOS中,只有一个目录跟传入的参数匹配,因此这个集合里面只有一个元素
NSString *documents = [array objectAtIndex:0];
tmp:NSString *tmp = NSTemporaryDirectory();
Library/Caches:(跟Documents相似的2种方法)
利用沙盒根目录拼接”Caches”字符串
利用NSSearchPathForDirectoriesInDomains函数(将函数的第2个参数改成:NSCachesDirectory便可)
Library/Preference:经过NSUserDefaults类存取该目录下的设置信息
属性列表
● 属性列表是一种XML格式的文件,拓展名为plist
● 若是对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可使用writeToFile:atomically:方法直接将对象写到属性列表文件中
属性列表-归档NSDictionary
// 将数据封装成字典
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:@"母鸡" forKey:@"name"];
[dict setObject:@"15013141314" forKey:@"phone"];
[dict setObject:@"27" forKey:@"age"];
// 将字典持久化到Documents/stu.plist文件中
[dict writeToFile:path atomically:YES];
属性列表-恢复NSDictionary
// 读取Documents/stu.plist的内容,实例化NSDictionary
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSLog(@"name:%@", [dict objectForKey:@"name"]);
NSLog(@"phone:%@", [dict objectForKey:@"phone"]);
NSLog(@"age:%@", [dict objectForKey:@"age"]);
偏好设置
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:@“yu3” forKey:@"username"];
[defaults setFloat:18.0f forKey:@"text_size"];
[defaults setBool:YES forKey:@"auto_login"];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *username = [defaults stringForKey:@"username"];
float textSize = [defaults floatForKey:@"text_size"];
BOOL autoLogin = [defaults boolForKey:@"auto_login"];
[defaults synchornize];
NSKeyedArchiver
每次归档对象时,都会调用这个方法。通常在这个方法里面指定如何归档对象中的每一个实例变量,可使用encodeObject:forKey:方法归档实例变量
每次从文件中恢复(解码)对象时,都会调用这个方法。通常在这个方法里面指定如何解码文件中的数据为对象的实例变量,可使用decodeObject:forKey方法解码实例变量
NSArray *array = [NSArray arrayWithObjects:@”a”,@”b”,nil];
[NSKeyedArchiver archiveRootObject:array toFile:path];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
对象的归档解档
@interface Person : NSObject<NSCoding>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) float height;
@end
@implementation Person
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeInt:self.age forKey:@"age"];
[encoder encodeFloat:self.height forKey:@"height"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self.name = [decoder decodeObjectForKey:@"name"];
self.age = [decoder decodeIntForKey:@"age"];
self.height = [decoder decodeFloatForKey:@"height"];
return self;
}
- (void)dealloc {
[super dealloc];
[_name release];
}
@end
Person *person = [[[Person alloc] init] autorelease];
person.name = @“yu3”;
person.age = 22;
person.height = 1.75f;
[NSKeyedArchiver archiveRootObject:person toFile:path];
Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
[super encodeWithCode:encode];
确保继承的实例变量也能被编码,即也能被归档
self = [super initWithCoder:decoder];
确保继承的实例变量也能被解码,即也能被恢复
NSData
使用archiveRootObject:toFile:方法能够将一个对象直接写入到一个文件中,但有时候可能想将多个对象写入到同一个文件中,那么就要使用NSData来进行归档对象
NSData能够为一些数据提供临时存储空间,以便随后写入文件,或者存放从磁盘读取的文件内容。可使用[NSMutableData data]建立可变数据空间
NSData-归档2个Person对象到同一文件中
// 新建一块可变数据区
NSMutableData *data = [NSMutableData data];
// 将数据区链接到一个NSKeyedArchiver对象
NSKeyedArchiver *archiver = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease];
// 开始存档对象,存档的数据都会存储到NSMutableData中
[archiver encodeObject:person1 forKey:@"person1"];
[archiver encodeObject:person2 forKey:@"person2"];
// 存档完毕(必定要调用这个方法)
[archiver finishEncoding];
// 将存档的数据写入文件
[data writeToFile:path atomically:YES];
// 从文件中读取数据
NSData *data = [NSData dataWithContentsOfFile:path];
// 根据数据,解析成一个NSKeyedUnarchiver对象
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
Person *person1 = [unarchiver decodeObjectForKey:@"person1"];
Person *person2 = [unarchiver decodeObjectForKey:@"person2"];
// 恢复完毕
[unarchiver finishDecoding];
利用归档实现深复制
// 临时存储person1的数据
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person1];
// 解析data,生成一个新的Person对象
Student *person2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
// 分别打印内存地址
NSLog(@"person1:0x%x", person1); // person1:0x7177a60
NSLog(@"person2:0x%x", person2); // person2:0x7177cf0
2015/11/5
Day 33
今天作了一个多控制器跳转的小项目
storyboard设计以下
页面的搭建和之间的跳转都是比较简单的,主要练习了一下利用偏好设置来实现记住密码以及自动登陆功能
首先在监听登陆按钮点击方法下加入
//利用preferences存储数据
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.userNameText.text forKey:@"username"];
[defaults setObject:self.pwdText.text forKey:@"pwd"];
[defaults setBool:self.rememberPwdSwich.isOn forKey:@"rememberPwd"];
[defaults setBool:self.autoLoginSwich.isOn forKey:@"autoLogin"];
[defaults synchronize];
这样就将数据存到偏好设置中了
而后在主控制器的viewDidLoad方法中加入
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.rememberPwdSwich.on = [defaults boolForKey:@"rememberPwd"];
self.autoLoginSwich.on = [defaults boolForKey:@"autoLogin"];
if (self.rememberPwdSwich.isOn) {
self.userNameText.text = [defaults stringForKey:@"username"];
self.pwdText.text = [defaults stringForKey:@"pwd"];
}
if (self.autoLoginSwich.isOn) {
[self loginBtnClick];
}