重点知识
Engadget(瘾科技)
StackOverFlow(栈溢出)
Code4Apprespon
魏先宇的程序人生
第一周
快捷键: Alt+上方向键 跳到最上面 Alt+下方向键 跳到最下面
Alt+左方向键 跳到最左面 Alt+右方向键 跳到最右面
Alt+shift+方向键 可以批量复制内容,在按方向键可以删除行
command+鼠标 纵向复制内容
userInteractionEnabled 控件的交互性;
类的三大特性 :工程名:首字母一定要大写,如果名字包含多个单词,则每个单词的首字母都要大写。
方法名: 命名规则和属性名(变量名)相同,第一个单词的首字母小写,以后的每个单词的首字母都要大写。
#import<> #import关键字,导入工具 <> 代表导入是系统的工具类的头文件 “” 代表导入的是自己的类的头文件
@"" 代表OC中的字符串
逻辑运算 &(与) |(或) !(非)
&& 并且 || 或者 ! 非 !YES = NO !NO = YES
对于c的函数,非void类型都要使用return return后面的代码都不再执行
Control reaches end of non-void function
控制到达了非空方法的末尾 表示此方法需要有返回值。必须使用return。
.h header 头文件 作用只是做类的声明,做属性的声明,不做赋值,做方法的声明,不做实现。 方法分为-实例方法和+类方法。 在类方法中是不允许访问属性(instance variable 实例变量)
.m main 主文件 实现文件 作用:.h不做了,我来做。 方法的实现和属性的赋值(属性的赋值是放在方法中完成)。
非ARC下)对于一个方法,在.h未声明,但是在.m中已经实现,则仍然可以调用。
执行类中的方法: OC调用方法都使用 [ ]
+(eat) 1 导入People头文件
2 调用+eat方法 [类名 类方法的方法名];
-(eat) 1 导入头文件
2 创建对象 People *p = [People alloc];
3 对象调用实例方法 [对象名 方法名];
Log 日志 %d %lld % i %f
%@ 对象类型(指针类型)
NSLog(@"=====%@",p2); =====<People: 0x100200960>
%p 输出指针保存的内存地址 pointer 指针
NSLog(@"=====%p",p2); =====0x1002063d0
声明多个参数的方法:
- (int)sum:(int)value1 withSecond:(int)value2;
//方法类型 (返回值类型)方法名部分1(参数1类型)参数1名 方法名部分2(参数2类型)参数2名....
属性用来使用 (设置属性值,获得属性值)
案例:设置一个人的年龄,并且设置之后获得设置后的年龄值。
只能通过方法访问属性值。
对于对象打点调用属性,所调用的set和get的方法的方法名是固定的:age属性: setAge age
set 和get方法
————————
对象调用set和get方法
————————
set 和get方法
对象名.属性名(代替调用set和get的方法的一种简易写方法)
————————
@[email protected](属性的声明和实现,代替属性set和get方法)
对象名.属性名
————————
同种类型的属性声明可以写在一起,用逗号分隔。
@property float height,weight;
@property int age;
@property bool sex;
@synthesize height,age,sex,weight;
如果类中存在属性的set和get方法,则对属性设置值和获得值时,可以使用两种方式:
1 对象调用set和get方法
2 对象打点调用属性 对象名.属性名
对象打点调用属性的本质调用属性的set和get方法。
在.h中声明的属性变量,在.m中的任何一个方法中都可以使用(+方法除外),这个属性变量一般叫做 全局变量。
全局变量(属性) 局部变量(某个方法中定义的变量)
局部变量会覆盖全局变量(变量名相同)
NSString 字符串类 声明变量 *
默认是nil ,在控制台上输出的是(null),指针指向的地址是0x0.
nil是一个对象指针为空,Nil是一个类指针为空,NULL是基本数据类型为空。
NSString 类型 共有的只有NSString,不共有*。
@property NSString *name,*name1;
内存管理 ARC Automatic Reference Counting
自动 引用 计数
Xcode 5.x 默认创建工程 支持ARC
关闭ARC: Building Setting ---搜索:auto---Objective-C 把ARC改成NO / gar 把ARC改成NO
(非ARC下)在.m中已经实现但在.h中未声明的方法仍然可以调用。
继承的特性:子类继承父类,会继承父类 所有的 属性和方法。
self 本类的对象 super 父类的对象
重写的init方法。
目的:把属性的初始化工作直接写在了init方法中。
自定义的initWithXX方法。
目的:可以对对象的属性进行赋值
强制类型转换 : (转换后的类型)需要转换的变量
float a = 3.14; int b = (int)a
强制类型转换只能转换指针类型,不能转换它的对象类型
People *p = [[People alloc] init];
p完成初始化之后再赋给p,那么这时的指针指向的对象就已经是完成初始化之后的对象。
init方法是完成系统最基本的初始化工作,比如优化内存等。
重写的init方法就能替代多参完成属性赋值的初始化操作。
+alloc -init 是NSObject的方法 People : NSObject
id OC中的弱类型 强 可以接收任意类型,一般接收对象类型(*)
alloc和init方法返回值类型都是id的原因是这里返回值不能是固定的类型(People*),任何NSObject的子类People调用alloc或init方法时都返回该类的对象,并且使用People类的指针接收。
- (id)init
{
self = [super init];
如果父类初始化成功,则完成 自己的初始化工作。
if (self) // if (self != nil)
{
// initialize code
age = 18;
sex = YES;
[self eat];
}
// 最后返回的self ,不仅完成了父类的初始化工作,而且也完成自己的初始化工作。
return self;
}
设置自己飞机的移动
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//获得touch事件
UITouch* touch = [touches anyObject];
//根据touch事件获得点的坐标
CGPoint point = [touch locationInView:self.window];
if (CGRectContainsPoint(myPlane.frame, point))
{
myPlane.center = point;
}
}
让键盘下去的方法:
1.[_loginPassWordTxt addTarget:self action:@selector(keyBoardLeave) forControlEvents:UIControlEventEditingDidEndOnExit]; 下面实现 keyBoLeave 方法时可以什么都不写
2.-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//当前view结束编辑
[self.view endEditing:YES];
//当textField失去焦点的时候,键盘也会下去
3.//[_userNameTxt resignFirstResponder];
}
局部变量的生命周期 从声明开始到方法的结束
for循环语句中 可以定义 static 静态变量 它只会被初始化一次 会保存在内存里面的 静态存储区
i++ i是先使用,后++ ++i i是先++,后使用
控件 窗口小部件(组件) 手机软件中的按钮,标签等,,
UI UserInterface 用户接口界面
1.标签 显示文字 2.按钮 点击用于触发事件
3. 文本框 输入文字
AppDelegate 应用程序代理类 入口类
入口类中的didFinishLaunching 入口方法 相当于代替了main方法。
CGRect (数据类型) 结构体
typedef(类型定义) struct CGRect CGRect;
typedef a b 用b代替a
如果想确定一个控件的位置,要么使用frame,要么使用bounds+center,仅仅设置bounds,那么默认center为(0,0),这样只会显示此控件的1/4(右下半)。
device 真机调试
3.5 inch iPhone4 4s 4 inch iPhone 5 5c 5s SE 4.7 inch iPhone 6 6s 5.5 inch iPhone 6s 6sp
ipad1,2 1024 * 768 9.7寸
ipad3 ,4 2048 * 1536
ipad mini 1024 * 768 7.9寸
ipad mini (retina)2048 * 1536
ipad air (ipad 5) 2048 * 1536 9.7寸
ipad模拟器: 1024*768
iphone 3.5inch 320* 480
iphone 4inch 320*568
iphone 4.7inch 375*667
iphone 5.5inch 540*960
第二周
Lab.textAlignment = NSTextAlignmentCenter; 设置字体居中
TextField.placeholder = @"请输入密码"; 设置隐藏编辑字符
TextField.secureTextEntry = YES; 设置是否安全键入
TextField.borderStyle = UITextBorderStyleRoundedRect; 设置边框样式 border 边角
TextField.clearButtonMode = UITextFieldViewModeAlways; 设置清除文本框
[t addTarget:self action:@selector(XX) forControlEvents:UIControlEventEditingDidEndOnExit]; 设置return键取消键盘
是否允许剪切 earth.clipsToBounds=YES;
这个值设置长宽高的一半 earth.layer.cornerRadius=20;
字符串判断是否相等 isEqualToString
去掉字符串中的空格和空白
str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]
返回参数字符串在原字符串中的位置和长度
//返回值是NSRange,类似于CGRect,CGPoint
//NSRange有两个属性,location,length
//location,参数字符串的第一个字符在原字符串中的位置
//length,参数字符串的长度
//如果原字符串不包含参数字符串,返回的NSRange的location的值为NSNotFound
if ([urlString rangeOfString:@"code"].location == NSNotFound) {};
//substringToIndex,截取字符串,从0开始,到index结束
//substringFromIndex,截取字符串,从index开始,到末尾结束
//substringWithRange,截取字符串,从location开始,长度为length
textView.text = [resultString substringToIndex:10];
#define 宏定义 分为 常量宏 函数宏
IBAction 绑定方法 IBOutlet 关键字 关联对象 (xib中在.h文件中写的)
如果xib文件被修改后 需手动加载xib文件 调用 [ ]initWithNibName:@“”……
获取window的方式:
1. UIWindow *window = [UIApplication sharedApplication].keyWindow;
2. AppDelegate * app =[UIApplication sharedApplication].delegate;
UIWindow *window = app.window;
3. NSArray *array = [UIApplication sharedApplication].Windows;
UIWindow *window = [array objectAtIndex : 0 ];
部分可用 self.view.window
字符串拼接来找图片的图片名 (格式化字符串)
NSString* imageName = [NSString stringWithFormat:@"Fire%d.gif",i];
根据图片名找图片放到fire的imageView上
fire.image = [UIImage imageNamed:imageName];
让定时器方法不再等待第一个时间差 [Timer fire];
暂时关闭定时器 [timer setFireDate:[NSDate distantFuture]];
再开启定时器 [timer setFireDate:[NSDate distantPast]];
永久关闭定时器 [timer invalidate]; timer = nil;
输出一个对象的CGRect , CGPoint ,CGSize :
NSLog(@"%@",NSStringFromCGRect(CGRect rect));
NSLog(@"%@",NSStringFromCGPoint(CGPoint point));
NSLog(@"%@",NSStringFromCGSize(CGSize size));
//输出字节数
NSLog(@"int---%lu",sizeof(int));
NSLog(@"long---%lu",sizeof(long));
第三周
开辟线程的两种方法
//开辟分线程的时候,绑定一个方法,让这个方法在分线程里面执行.
[NSThread detachNewThreadSelector:@selector(new) toTarget:self withObject:nil];
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(new) object:nil]; 通过alloc 方法开辟线程 需要去调用start方法 [thread start];
解决多个线程同时访问一个数据(类比 多个卖票点同时卖一张火车票),
1.NSLock 加线程锁,
// _lock = [[NSLock alloc] init];
// [_lock lock];
线程队列执行
// [_lock unlock];
2,线程同步块 @synchronized(self)
分线程中不能开启 Timer
分线程中不会执行UI的更新,要回到主线程去更新 [self performSelectorOnMainThread:(SEL) withObject:(id) waitUntilDone:(BOOL)];
waitUntilDone: 为yes 让分线程等待,直接去主线程中执行,执行完毕后继续执行当前的分线程
为NO, 分线程执行结束再去执行主线程
当前线程休眠 [NSThread sleepForTimeInterval:(NSTimeInterval)];
[Thread MainThread]; [Thread currentThread]; //判断当前线程是否为主线程,返回值为 BOOL类型 [NSThread isMainThread];
12.31号 :// 获取URL地址上的data 方法 是一个同步的方法
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b.hiphotos.baidu.com/image/pic/item/e4dde71190ef76c666af095f9e16fdfaaf516741.jpg"]];
//perform 执行, 在主线程中执行一个方法,可以传一个参数给这个方法
// 拿到数据之后 回到主线程刷新UI 分线程不能刷新UI
[self performSelectorOnMainThread:@selector(setImageViev:) withObject:data waitUntilDone:YES];
3,操作队列:
//用操作队列可以解决线程同步的问题,如果有多个操作的话,每个操作随机先执行,执行完一个操作之后才去执行另外一个操作,不会出现一个数据同时被多个操作访问的情况.
// 创建一个操作 绑定相应的方法,当把操作添加到操作队列中时 操作绑定的方法就会自动执行了
// 创建一个操作队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 1,系统提供的操作
// 调用操作
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomeThing) object:nil];
// 把操作添加到操作队列中
[queue addOperation:operation1];
设置导航栏标题
第一种
self.title = @"setting";
第二种
self.navigationItem.title = @"1111";
第三种
UILabel *lab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
lab.text = @"111222";
lab.backgroundColor = [UIColor redColor];
self.navigationItem.titleView = lab;
设置导航栏右边按钮选项
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(buttonClick:)];
self.navigationItem.rightBarButtonItems = rightButton ;
跳转到下一个界面
1. SecondViewController *secondVC = [[SecondViewController alloc] init];
[self.navigationController pushViewController:secondVC animated:YES];
2.模态弹出
SecondViewController *secondVC = [[SecondViewController alloc] init];
[self.navigationController presentViewController:secondVC animated:YES completion:nil];
(如果使用模态弹出,此时没有导航栏且ViewController 不会被加载到导航控制器中,那么就不能使用pop方法) 若想返回上一个界面,要使用
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
//模态弹出的样式( 非全屏 formSheet,pageSheet)
vc.modalPresentationStyle = UIModalPresentationFormSheet;
//模态弹出的动画方式
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
返回到上一个界面
[self.navigationController popViewControllerAnimated:YES];
返回到根视图界面
[self.navigationController popToRootViewControllerAnimated:YES];
返回到指定视图界面
(获取导航器中的所有导航控制器) NSArray *array = self.navigationController.viewControllers;
[self.navigationController popToViewController:[array objectAtIndex:0] animated:YES];
在一个数组中插入数组
NSMutableArray *array1 = [NSMutableArray arrayWithObjects: @"one", @"two", @"three", @"four", nil];
NSArray *newAdditions = [NSArray arrayWithObjects: @"a", @"b", nil];
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSetWithIndex:1];[indexes addIndex:3];
// indexes 1 3
[array1 insertObjects:newAdditions atIndexes:indexes];
NSLog(@"array: %@", array)
// Output: array: (one, a, two, b, three, four)
替换多个索引值的对象
(NSIndexSet *) 索引
[arr replaceObjectsAtIndexes:(NSIndexSet *) withObjects:(NSArray *)];
从第二界面回到第一界面时 此时viewdidload方法不再执行,因为视图已经加载过了
此时需要重写viewWillAppear(视图将要显示)
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"从第二个页面得到的内容 %@",self.fromSecondText);
// 把第二界面的内容赋值给text1
text1.text = self.fromSecondText;
}
判断从数组中取的对象是否是( )类型的对象用 iskindOfClass
ScrollView.contentSize (容量大小)
设置水平竖直方向的标示符
scrollView.showsHorizontalScrollIndicator = YES;
scrollView.showsVerticalScrollIndicator = YES;
设置是否可以分页
scrollView.pagingEnabled = YES;
设置是否回弹
scrollView.bounces = YES;
设置偏移量 (向左为正 向右为负)
scrollView.contentOffset = CGPointMake(30, 0);
设置拖动过程中水平或者垂直方向能否被锁定
scrollView.directionalLockEnabled = YES;
设置 scrollView 四个边界的预留空白区域
scrollView.contentInset = UIEdgeInsetsMake(40, 40, 0, 0);
ScrollView中实现图片的缩放
设置它的最大放大比例(长和宽)
_scrollView.maximumZoomScale = 4;
_scrollView.minimumZoomScale = 0.25;
返回需要缩放的 View,这个 View 必须是 scrollview 的子 View,实现了这个方法,scrollview 就可以实现缩放了。 如果使用了 scrollView 的缩放功能,就不能再用它的滑动效果,否则会乱。
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return _imageView;
}
当 scrollView 已经缩放时的回调
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
//_imageView.center = self.view.center;(缩小的时候可以用)
if (scrollView.zoomScale<1)
{
float width = _scrollView.frame.size.width*(1-scrollView.zoomScale)/2;
float height = _scrollView.frame.size.height*(1-scrollView.zoomScale)/2;
scrollView.contentInset = UIEdgeInsetsMake(height, width, 0, 0);
}
}
PageControl.numberOfPages 设置页数(几个点)
PageControl.currentPage 当前的页数
系统 tabBar的选项
pay.tabBarItem = [[UITabBarItem alloc]initWithTabBarSystemItem:UITabBarSystemItemRecents tag:1];
若要给它换图片,用
pay.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"pay" image:[UIImage imageNamed:@"1"] selectedImage:[UIImage imageNamed:@"1"]];
给tabBar 设置多个视图控制器
NSArray *vcArray = @[nav1,nav2,nav3,nav4,five,six];
tabBarController.viewControllers = vcArray;
设置当前选中的索引
tabBarController.selectedIndex = 0;
1.创建多个视图控制器
2.创建UITabBarController的实例
3.把UITabBarController的对象做为根视图添加到window上
4.将所有的视图控制器添加到tabbar上
5.设置tabbar中的item
设置样式
toolBar.barStyle = UIBarStyleDefault;
UIBarButtonItem *barButton1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:Nil];
设置BarButtonItem 之间的固定空间
UIBarButtonItem *FixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:self action:Nil];
宽度 FixedSpace.width = 20;
NSArray *itemArray = @[FixedSpace,barButton2,FixedSpace,barButton3];
[toolBar setItems:itemArray animated:YES];
ActionSheet 中的按钮是从上到下来按顺序设置索引值的
AlertView 中的按钮中“取消”的索引值是0,其他的按顺序设置
若要使用系统的代理方法,要在.h 文件声明类的后面加上<UI XXX Delegate>
第四周
代理
如果一个页面以及上面的内容会在不同的时候出现,此时可以把这个相同的东西封装到一个类当中, 若此页面出现的时候需要调用一些方法,此时为了区分它们,我们可以在封装类的头文件中声明一个 id 类型的对象(delegate),并在@end 下面用@protocol声明此对象的方法(此方法的实现内容在具体出现的页面中实现),让其在需要用的时候调用。
@end
@protocol XXXDelgate <NSObject>
@optional
- (void)myView:(UIView *)myView clickedButtonAtIndex:(NSInteger)buttonIndex;
@end
继承于 UIView的类所创造的对象可以打点调用 hidden 设置为 YES 让其隐藏。
数据源 pickerView.dataSource = self; 有两个必须实现的方法
代理 pickerView.delegate = self;
[pickerView selectedRowInComponent:0]; 获得第0区的第Row行
刷新第一个区 [pickerView reloadComponent:1];
选中第1区的第0行[pickerView selectRow:0 inComponent:1 animated:YES];
#pragma mark 杂注
设置样式
datePicker.datePickerMode = UIDatePickerModeDateAndTime;
获取picker的时间
NSDate *date = picker.date;
创建时间格式化器
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
设置date的格式
[dateFormatter setDateFormat:@"yyyy-MMMM-dd-EEE-aa"];
把时间转换成字符串
NSString *dateString = [dateFormatter stringFromDate:date];
yy: 年的后2位 yyyy: 完整年
MM: 月,显示为1-12 MMM: 月,显示为英文月份简写,如Jan MMMM: 月,显示为英文月份全称,如Janualy
dd: 日,2位数表示,如02 d: 日,1-2位显示,如 2
EEE: 简写星期几,如Sun EEEE: 全写星期几,如Sunday
aa: 上下午,AM/PM
H: 时,24小时制,0-23
K:时,12小时制,0-11
m: 分,1-2位 mm: 分,2位
s: 秒,1-2位 ss: 秒,2位 S: 毫秒
Z: 时区
常用日期结构:
yyyy-MM-dd HH:mm:ss.SSS
yyyy-MM-dd HH:mm:ss
yyyy-MM-dd
MM dd yyyy
第五周
获取标题宽度
width = button.titleLabel.frame.size.width;
UIFont *font = [UIFont systemFontOfSize:17];
CGSize size = [@"百度" sizeWithFont:font];
webView 网页视图
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[self.view addSubview:_webView];
// 创建 链接
NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"];
// 创建请求
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
// 加载请求
[_webView loadRequest:request];
不能深度赋值
应该这样:CGRect rect = rainImage.frame;
rect.origin.y = 305;
rainImage.frame = rect;
如果把 Image 盖在 button 上面,在 image 上点击 button 效果还会被触发,如果是把 View 盖在上面,button 效果不会被触发。
UITableView
设置分割线的颜色 tableView.separatorColor
实现表的数据源方法
下面黄色部分可以相互代替(写在 tableView 的创建后面)
给 tableview 的 ReuseIdentifier 注册一个 cell类,当 tableview 找不到可以重用的 cell 时,就会自动创建一个这种类型的 cell
[_table registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = @"cell";
// 在队列中查询有没有可以重用的单元格
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
// 如果没有单元格 就去创建新的单元格
if (!cell)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
return cell;
}
如果是自定义表加载 xib 时,要用
if (!cell)
{
//手动加载xib文件
NSArray *array = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:Nil options:Nil];
//强转
cell = (CustomCell *)[array objectAtIndex:0];
}
自定义区头后一定要记得设置区头和区尾的高度
// 设置索引标题
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return _array;
}
// 完成编辑
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
(此方法写上以后向右划定单元格会出现删除按钮,移除单元格的方法也就写在这个方法里面)
}
//设置是否可以移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
//改变数据
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
找到sourceIndexPath所在的位置(区、行)并把它从当前的数组中移除,然后把 sourceIndexPath加入到destinationIndexPath所在的位置(区、行),完成操作后一定要刷新表
}
刷新表的两种方法:
1.[_tableView reloadData];
2. NSIndexSet 索引集合 把将要改变的区加入到索引集合中 NSMutableIndexSet 可变的索引集合
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSetWithIndex:section];
[_tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
第二种方法比较高效
刷新表的时候,表的数据源方法和代理方法都要重新执行一次
Rotation 旋转
顺时针旋转90
Button.transform = CGAffineTransformMakeRotation(M_PI_2);
transform默认为CGAffineTransformIdentity
// 获取最后一行的索引
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_messageArray.count - 1 inSection:0];
// _tableView滑动
[_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
// 自适应高度
CGRect rect = [contentText boundingRectWithSize:CGSizeMake(160, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:17]} context:Nil];
UIImage *old = _whoSay ?[UIImage imageNamed:@"bubbleSelf"]:[UIImage imageNamed:@"bubble"];
UIImage *image = [old stretchableImageWithLeftCapWidth:10 topCapHeight:10];
imageView.image = image;
第六周
NSNumber 能够把基本类型的数据包装成一个对象,此对象可以存进数组。
_sectionOpenArray = [[NSMutableArray alloc]initWithObjects:[NSNumber numberWithBool:NO], [NSNumber numberWithBool:NO],[NSNumber numberWithBool:NO],nil];
利用 NSNumber 实现 BOOL 值的转换来改变tableView 中区的打开与关闭
[_sectionOpenArray replaceObjectAtIndex:button.tag withObject:[NSNumber numberWithBool:![[_sectionOpenArray objectAtIndex:button.tag] boolValue]]];
设置 alert 的样式,不同样式上面的 textfield 数量和类型不同
alert.alertViewStyle = UIAlertViewStylePlainTextInput;
[alert textFieldAtIndex:0].placeholder = @"用户名";
用 alert 在 tableView 中添加一个分组
if (alertView.tag == 100)
{
//首先在好友数组中添加一个新的数组,用来存放这个区的好友
[_friendArray addObject:[NSMutableArray arrayWithCapacity:0]];
//然后再分组名称数组中添加这个新分组的名字
NSString *name = [alertView textFieldAtIndex:0].text;
[_sectionNameArray addObject:name];
//最后在控制打开关闭的数组中给这个新区添加一个 NSnumber,用来标记它的打开状态
[_sectionOpenArray addObject:[NSNumber numberWithBool:NO]];
[_table reloadData];
}
//从 iOS7 开始,状态栏和 navigationBar 与 viewController 合为一体(ViewController 的 View 左上角从屏幕左上角开始),为了保证 tableview 或者 scrollView 顶部的内容不被 navigationBar 挡住,ViewController回自动给自身上的 scrollerView 顶部添加64的 inset,如果不需要这个 inset,automaticallyAdjustsScrollViewInsets设置为 NO 即可。
self.automaticallyAdjustsScrollViewInsets = NO;
_table.contentInset = UIEdgeInsetsMake(64, 0, 0, 0);
//刷新控制器
UIRefreshControl *control = [[UIRefreshControl alloc] init];
//设置菊花颜色
control.tintColor = [UIColor redColor];
//设置下拉刷新标题
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:@"下拉刷新"];
[str setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont systemFontOfSize:20],NSFontAttributeName,[UIColor redColor],NSForegroundColorAttributeName, nil] range:NSMakeRange(0, 4)];
control.attributedTitle = str;
//把刷新控制器和tableViewController结合
self.refreshControl = control;
//停止下拉刷新的转动动画
[self.refreshControl endRefreshing];
为什么要管理内存?
计算机的内存是有限的,如果我们需要使用一个对象,会在内存中创建这个对象,内存使用量就会越来越多,如果只创建,不去释放,那么就会造成内存撑爆。所以,我们在使用一个对象时创建,不再使用这个对象时,要把它释放。
不同语言管理内存的方式
Java:全自动内存管理:Java 运行时,每隔一段时间就会自动检查内存当中的所有对象,当发现不再使用的对象时,就会把这个对象从内存中释放。这个功能叫做 Java 垃圾回收机制。这种内存管理机制使用方便,但是运行效率低。
C++:全手动内存管理:当需要使用一个对象时创建,确定不再使用这个对象时,手动把它释放掉。这种内存管理机制使用麻烦,但是运行效率高。
OC:通过引用计数来管理内存(半自动管理内存):对象的引用计数就是标记当前有多少个其他对象正在使用这个对象。当其他对象需要使用这个对象时,要把这个对象的引用计数加1,当某个其他对象不再使用这个对象时,要把这个对象引用计数减1。一旦某个对象的引用计数为0,那么它就会被系统释放掉。
*全局指针需要在dealloc中release。 *局部指针需要在方法结束前release
super dealloc目的是释放掉父类的全局指针指向的对象。
super dealloc必须写在最后,因为要先释放自己的全局属性,再释放父类的全局属性
通过alloc,new,copy创建出来的对象,引用计数为1 其他的方式创建的对象,都是延迟释放的。 new就相当于alloc+init
retain方法使一个对象引用计数+1 release方法使一个对象引用计数-1
如果一个指针指向了一个对象,那么这个指针指向另外一个对象时,需要先把之前指向的对象release一次。否则就会导致内存泄露。
*引用计数管理原则:谁创建,谁释放,谁使用,谁管理。
alloc的数量+retain的数量=release的数量
把对象放进数组后,数组会对这个对象的引用计数+1
当数组移除某个对象时,这个对象的引用计数-1
当数组将要被释放时,会对这个内部的所有对象release一次。
当一个视图添加到父视图上时,父视图会对这个视图引用计数+1
当一个视图将要被释放时,会对自己的所有子视图release一次。
用buttonWithType创建的button,addSubview之后不需要release
alertView show之后会导致alert引用计数增加。 alertView show之后立刻release
模态弹出一个vc之后,vc的引用计数会增加。 vc模态弹出或者push之后立刻release
*如果property为retain(copy)形式,当打点调用赋值时,会先对之指向的对象release一次,再对新指向的对象retain(copy)一次
对于对象的set方法,需要先对之前的对象release一次,然后对新的对象retain一次
对于全局的timer一般需要在界面消失的时候停止,而不是dealloc中停止,因为timer如果不停止,那么timer的target就不会释放。dealloc就不会执行。
NSTimer只要还在执行,即使引用计数为0,也不会被释放,直到timer停止才可能被释放。
UIImage的imageNamed方法虽然是延迟release的,但是并不会在事件循环结束的时候release。
delegate的property要用assign描述,否则会导致循环引用,最后两个对象都释放不掉
//用storyboard设计的viewController需要用UIStoryboard加载
UIStoryboard *board = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ViewController *vc = [board instantiateInitialViewController];
单例类
1、单例类只有一个实例(对象)
2、单例类必须提供一个获得这个唯一实例的方法
3、单例类能够自动创建这个唯一的实例
自定义单例类
static Singleton *__singleton = nil;
+(Singleton *)defaultSingleton{
//为了防止多个线程同时判断单例是否存在,从而导致同时创建单例。判断的时候必须加线程同步。
@synchronized(self){
if (!__singleton) {
__singleton = [[Singleton alloc] init];
}
}
return __singleton;
}
//为了防止人为创建单例类,重写alloc方法。
+ (id)alloc{
//dispatch_once 的block中的代码当程序运行后只会被执行一次。
//单例类的创建最好用dispatch_once。
//使用dispatch_once就不需要再进行判断,也不需要关心线程同步。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__singleton = [super alloc];
});
return __singleton;
}
通知是 iOS中的一种调用机制,当发送通知时,不需要关心谁来接收,需要接收这个通知的对象需要自己去监听这个通知。
通知和代理的区别:相同之处,都可以实现回调,都可以传参。不同之处,代理只能一对一调用,而且必须明确代理对象,通知可以实现多对多调用,而且不需要关心通知的接收者;代理的协议方法可以有返回值,但是通知的调用方法不能加返回值。
UIApplication就是单例类,我们使用的时候没有alloc 而是通过sharedApplication找到单例对象[UIApplication sharedApplication]
NSNotificationCenter是单例类。通知中心类似于广播站,发送任何通知都必须通过通知中心发送。
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
//字典,也是一种对象的容器,和数组不同的是,数组中的对象按照顺序存储,而字典中的对象按照键值对存储。
NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:color,@"color", nil];
//NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:color,@"color", nil];
//postNotification,发送一个通知
//第一个参数name是发送的通知的名字,用来区分不同的通知。
//第二个参数object是通知的发送者,一般都写self
//第三个参数是通知的参数,用来传参.
[center postNotificationName:@"changeColor" object:self userInfo:dic];
//addObserver添加一个监听者(让某个对象可以接收通知)。
//第一个参数observer就是添加的监听者,就是让哪个对象去接受通知
//第二个参数selector当监听者收到通知时调用的方法。
//第三个参数name,监听的通知名字,只监听哪个通知。
//第四个参数object,限定通知来源(只接受某个对象发的通知),如果不限定,写成nil
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveChangeColorNotification:) name:@"changeColor" object:nil];
- (void)receiveChangeColorNotification:(NSNotification *)noti
{
//当收到通知时调用方法会传过来一个NSNotification类型的参数,这个参数包含了name,object,和userInfo。
self.view.backgroundColor = [noti.userInfo objectForKey:@"color"];
}
removeObserver取消所有的通知监听。
*当一个对象将要被释放时,如果这个对象注册有监听通知,那么在释放前(也就是dealloc中)必须取消所有的监听,否则就会导致程序崩溃
[[NSNotificationCenter defaultCenter] removeObserver:self];
- (void)introduceSelf
{
NSLog(@"%@",self);
}
//description方法用来设置NSLog这个对象时输出的内容。如果不设置,默认输出为内存地址
- (NSString *)description
{
return [NSString stringWithFormat:@"我叫%@,今年%d岁,性别%@",_name,_age,[email protected]"男":@"女"];
}
//UIApplicationDidEnterBackgroundNotification应用程序已经进入后台的通知。
//UITextFieldTextDidChangeNotification输入框中内容改变时的通知
//UIKeyboardWillChangeFrameNotification键盘的frame将要发生改变的通知
NSValue能够把结构体封装成对象,就可以放入数组或字典。
NSValue *value = [noti.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
//获得键盘的坐标
CGRect rect = [value CGRectValue];
//获得动画时间
float duration = [[noti.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
int curve = [[noti.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
数据的存储
沙盒:在存储器中一块独立的空间,这个空间中存储了一个应用,以及这个应用的数据,那么这块空间就叫做这个应用的沙盒。
沙盒运行模式:应用程序在运行时,对硬盘的操作权限仅限于自己沙盒内部,不能对沙盒外部的空间进行直接操作。
沙盒内部有4个文件夹, Documents,library,tmp,app Documents 存储应用的文档文件,对于开发者最常用. library 存储应用设置或配置的相关信息,也存储一些系统数据,提供给系统使用,一般情况下不在这个文件夹下存储文件. tmp 临时文件夹,用来存储一些临时文件 app 应用资源文件夹,存储应用所需要的所有资源,此文件夹只能读,不能修改.
1.使用NSUserDefaults存储数据
// NSUserDefaults 用户数据存储器,常用来存储和一些用户信息或用户设置有关的一些数据
// NSUserDefaults 单例类
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
// NSUserDefaults 类似字典,但不是字典,它可以存对象,还可以存基本类型.
[user setObject:name forKey:@"name"];
[user setInteger:age forKey:@"age"];
[user setBool:sex forKey:@"sex"];
// NSUserDefaults 修改后必须立刻同步一次(存储到硬盘),否则修改无效.
[user synchronize];
// NSUserDefaults 中的内容存储在沙盒下 library 文件夹中
从 NSUserDefaults 中读取数据
NSString *name = [[NSUserDefaults standardUserDefaults] objectForKey:@"name"];
int age = [[NSUserDefaults standardUserDefaults] integerForKey:@"age"];
BOOL sex = [[NSUserDefaults standardUserDefaults] boolForKey:@"sex"];
_name.text = name;
_age.text = [NSString stringWithFormat:@"%d",age];
_sexControl.selectedSegmentIndex = sex;
2.使用数组存储数据
NSArray *array = [[NSArray alloc]initWithObjects:name,_age.text,[email protected]"男":@"女", nil];
//Directory (计算机文件或程序)的目录
//Appending 附加 添加 贴上 Component 构成 成分
//NSHomeDirectory()找到当前应用的沙盒路径。
//stringByAppendingPathComponent当一个路径后追加路径。
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/abc.xml"];
//writeToFile 把数据存入文件,第一个参数是路径名,第二个参数是是否原子性(是否使用临时文件存储).
[array writeToFile:path atomically:NO];
[array release];
//文件名的后缀和文件内容没有关系,后缀仅仅是标记了这个文件的类型,也就是这个文件应该用什么工具去打开.
从文件当中读取数组.
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/abc.xml"];
NSArray *array = [[NSArray alloc]initWithContentsOfFile:path];
_name.text = [array objectAtIndex:0];
_age.text = [array objectAtIndex:1];
_sexControl.selectedSegmentIndex = [[array objectAtIndex:2] isEqualToString:@"男"]?0:1;
//判断某个文件是否存在
[[NSFileManager defaultManager]fileExistsAtPath:directoryPath]
//创建一个文件夹
[[NSFileManager defaultManager ] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:nil];
//创建一个文件
[[NSFileManager defaultManager]createFileAtPath:filePath contents:nil attributes:nil];
3.使用字符串拼接存储数据
NSString *string = [NSString stringWithFormat:@"%@|%@|%@",name,_age.text,[email protected]"女":@"男"];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/string.txt"];
//把字符串存入文件,第一个参数是存储路径,第二个参数是原子性,第三个参数是编码方式,iOS 的默认编码方式是 UTF8编码,第四个参数是如果写入失败,失败的原因.
[string writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:nil];
3.
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/string.txt"];
NSString *string = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//按照某个字符串分割成一个长字符串,得到一个数组,数组中就是分割成的若干个字符串.
NSArray *arr = [string componentsSeparatedByString:@"|"];
_name.text = [arr objectAtIndex:0];
_age.text = [arr objectAtIndex:1];
_sexControl.selectedSegmentIndex = [[arr objectAtIndex:2] isEqualToString:@"男"]?0:1;
[string release];
NSUserDefaults只能存系统自带的数据类,例如NSArray,NSString,int,BOOL等,自定义的类不能存。
NSArray(NSDictionary)只有当存储的对象都是系统自带的数据类时,才可以writeToFile,如果数组中存有自定义类,那么就不能writeToFile.
NSData数据类,存储了一段二进制数据。NSDate可以直接存入文件
//对于自定义类,如果想存入文件,必须先转化为二进制数据。这个转化的过程叫做对象序列化。
//只有实现了NSCoding协议,这个类才能被转化为二进制数据
//NSKeyedArchiver编码器,能够把实现了NSCoding协议的对象编码成二进制数据.
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:p];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.plist"];
[data writeToFile:path atomically:NO];
从文件中读取NSData
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.plist"];
NSData *data = [NSData dataWithContentsOfFile:path];
//NSKeyedUnarchiver解码器,能够把二进制数据还原成原来的对象。
People *p = [NSKeyedUnarchiver unarchiveObjectWithData:data];
_nameField.text = p.name;
_ageField.text = [NSString stringWithFormat:@"%d",p.age];
_sexControl.selectedSegmentIndex = p.sex;
实现 NSCoding 协议(先在.h 文件中用<NSCoding>在想要实现的类后追加)
//编码方法。
- (void)encodeWithCoder:(NSCoder *)aCoder{
//如果父类也遵守NSCoding协议,需要先调用super encodeWithCoder
//在编码方法中,把需要编码的数挨个进行编码
[aCoder encodeObject:_name forKey:@"name"];
[aCoder encodeInt:_age forKey:@"age"];
[aCoder encodeBool:_sex forKey:@"sex"];
}
//解码方法。
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super init];
//在解码方法中,对编码过的属性逐一解码
if (self) {
_name = [[aDecoder decodeObjectForKey:@"name"] copy];
_age = [aDecoder decodeIntForKey:@"age"];
_sex = [aDecoder decodeBoolForKey:@"sex"];
}
return self;
}
指针本身也是个变量,也需要占用内存,所以指针本身也有内存地址。
// NSString **str;两个星的指针叫做双指针,也就是指向指针的指针(指向指针的内存地址)。
&取地址符,获得一个指针的内存地址
//NSString **dString = &string;
/方法传参时如果要传递一个指针,那么不能直接写这个指针,因为写成指针实际传递的是这个指针指向的对象,所以如果要传递指针,参数必须写成指向这个指针的指针。
// NSFileManager 文件管理器,对文件进行删除,移动,复制,剪切等操作。
//NSFileManager也是单例类
NSFileManager *manager = [NSFileManager defaultManager];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/string.txt"];
NSError *err = nil;
//删除一个文件,如果删除失败,输出失败的原因
if (![manager removeItemAtPath:path error:&err]) {
NSLog(@"%@",err);
}
/创建文件夹
NSFileManager *manager = [NSFileManager defaultManager];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/abc/123"];
//withIntermediateDirectories是否自动创建路径中不存在的文件夹。
[manager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
//查看文件属性
- (IBAction)checkFileAttribute:(UIButton *)sender
{
NSFileManager *manager = [NSFileManager defaultManager];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/string.txt"];
NSDictionary *dic = [manager attributesOfItemAtPath:path error:nil];
NSLog(@"%@",dic);
}
UIImagePickerController 图片选择器
把图片转化成data的
NSData *data = UIImageJPEGRepresentation(_imageView.image, 0.5);
//图片可编辑
controller.allowsEditing = YES;
第七周
//FMDB是对sqlite3的封装,内部使用的也是sqlite3,所以要使用FMDB,需要先导入sqlite3库
//FMDatabase数据库操作类,可以打开或创建一个数据库文件。
FMDatabase *_db;
//打开或创建一个数据库文件
_db = [[FMDatabase alloc]initWithPath:[NSHomeDirectory() stringByAppendingPathComponent:@"Documents/data.sqlite"]];
//打开数据库
[_db open];
//在这个数据库中创建一张表 executeUpdate 执行一条修改语句
[_db executeUpdate:@"CREATE TABLE IF NOT EXISTS people(peopleID INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,phone TEXT)"];
//FMResultSet 结果集,查询出来的数据有可能很多条,所以放在了一个结果集中
FMResultSet *set = [_db executeQuery:@"SELECT * FROM people"];
//next 方法前往下一条记录,如果存在下一条记录返回 YES,不存在返回 NO.存在这条记录的话,把此记录封装成 people 对象,装进数组.(通过 while 循环遍历结果集)
while ([set next])
{
People *p = [[People alloc]init];
p.name = [set stringForColumn:@"name"];
p.peopleID = [set intForColumn:@"peopleID"];
p.phone = [set stringForColumn:@"phone"];
[_array addObject:p];
[p release];
}
[set close];
//关闭数据库
[_db close];
//把新添加的人写入数据库
[_db open];
//FMDB中 SQL 语句的占位符(?)只能用 NSString 替代,不能用 int
[_db executeUpdate:@"INSERT INTO people(name,phone)VALUES(?,?)",p.name,p.phone];
//SELECT MAX(peopleID) 搜索表中最大的peopleID,
FMResultSet *set = [_db executeQuery:@"SELECT MAX(peopleID) FROM people"];
[set next];
int maxID = [set intForColumnIndex:0];
p.peopleID = maxID;
//执行删除操作时,要先从数据库中删除
People *p = [_array objectAtIndex:indexPath.row];
[_db open];
[_db executeUpdate:@"DELETE FROM people WHERE peopleID=?",[NSString stringWithFormat:@"%d",p.peopleID]];
[_db close];
/*----这两个方法配套使用,是 UIViewController 的方法*/
- (BOOL)shouldAutorotate{
return YES;
}
//设置支持的屏幕方向
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
/*----_________________*/
获取屏幕的旋转角度
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
设置标签的旋转(到的)角度
lab.transform = CGAffineTransformMakeRotation( 270 * M_PI/180);
第八周
通讯
是客户端与服务器之间的通信
服务器(客户端):1.安装了服务器(客户端)软件的电脑 2.服务器(客户端)软件
IP 地址:Internet protocol 网络传输协议的逻辑地址
IPv4 地址是由4个 0到255 的数字组成
互联网中一台计算机发出的数据通过 IP 地址才能把数据准确的发送到另外一台计算机
域名,俗称网址,为了方便记忆和输入,进行通信时,不直接使用 IP 地址,而是使用域名.
DNS 服务:域名解析服务,能够把域名解析为 IP 地址
MAC地址:Media Access Control 接入互联网计算机的物理地址或网卡地址 通过物理地址识别主机
端口号: 是计算机与外界通讯交流的出口。 物理接口,协议端口 192.169.0.1:80 冒号后面的就是端口号
在计算机上运行的软件如果需要上网,就必须有一个端口号,用来区分网络返回的数据用于哪个软件。范围0-65535。一些号被特定的使用如:用于网络的80端口,用于FTP服务的21端口。
HTML:Hyper Text Mark-up Language 超文本标记语言,用来设计一个网页,任何网页的实质都是 html 标签对.
URL:唯一资源标识符.(链接地址) 代表一个资源的位置。可以是网络上的,可以是本地的。
http协议: 超文本传输协议
http传输 以报文形式传输, 分为请求报文和响应报文
请求报文分为请求行,请求头,和请求体。
请求行:请求方式(GET,POST)空格 IP 地址后的url 空格 http 版本
回车
请求头:contentLength = 0 connection = “close”
回车
回车
请求体:请求内容,可以为空也可以传数据
telnet localhost 8080
GET /MyServer/ HTTP/1.0
Host=localhost
Connection=close
//把接收到服务器返回的data类型的数据 转换成String类型的数据
NSString *str = [[NSString alloc] initWithData:_buffer encoding:NSUTF8StringEncoding];
NSLog(@"str %@",str);
响应报文
1.响应行:HTTP 版本 响应状态码(2XX 正常响应 4XX 异常响应)
GET 请求:把请求的参数写在请求的 url 之后,在 url 最后加?然后后面写参数,参数与参数之间用&分割(url?XXX=XXX&XXX=XXX)
GET请求参数长度受限,而且不安全.
POST 请求:把参数写在请求体中,这种请求方式相对安全.
JSON数据
[]表示数组
{}表示字典
[{name:张三,qq:123,sign:我今年5岁了},{name:李四,qq:333,sign:我捡了100块}]
OAuth 2.0认证过程
1.客户端从新浪微博请求一个认证界面,然后将这个认证界面呈现给用户。
2.用户在认证界面填写完账号密码并点确定时,认证界面会把账号密码直接发送给新浪微博(不通过客户端)。
3.新浪微博验证用户输入的账号密码,如果输入正确,新浪微博回交给客户端一个 code。
4.客户端拿到 code 之后,用 code 去请求 token。
token 就是这个用户的通行证。
在当前时间的基础上加上一个时间
NSDate *date = [[NSDate date] dateByAddingTimeInterval:expires.doubleValue]
//dateWithTimeIntervalSinceNow
//于现在相隔多少秒的一个时间
//正数,多少秒后,负数,多少面前
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:[expires intValue]];
比较两个时间的大小 NSOrderedDescending降序 说明前者比后者大
[date compare:nowDate] == NSOrderedDescending
//实现断点下载,首先要获取已经下载的文件的大小。
NSDictionary *att = [[NSFileManager defaultManager] attributesOfItemAtPath:[self filePath] error:nil];
unsigned long long size = [att fileSize];
//*当继续下载时,应该告诉服务器,客户端已经下载好了一部分数据,只需要把下载好的数据后面的数据传输过来即可。
//*请求头中Range代表下载的范围,从总数据的第几个字节之后开始下载就写成xx-
[request addValue:[NSString stringWithFormat:@"bytes=%qu-",size] forHTTPHeaderField:@"Range"];
上传文件或图片时,要用到固定的HeaderField
[request addValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
//UIImagePNGRepresentation把一个UIImage转成png格式的 NSData。
//UIImageJPEGRepresentation把一个UIImage转成jpg格式的 NSData。
//0.7是压缩比例,把图片压缩后转成DATA
NSData *data = UIImageJPEGRepresentation(_imageView.image, 0.7);
//把需要上传的数据放入请求体
[request setHTTPBody:data];
unsigned long long size = [att fileSize];
//告诉服务器上传的文件的大小
[request addValue:[NSString stringWithFormat:@"%qu",size] forHTTPHeaderField:@"Content-Length"];
//生成一个文件的输入流
NSInputStream *stream = [NSInputStream inputStreamWithFileAtPath:path];
//当上传大文件时,为了节省内存,不直接把所有数据都读入内存,而是使用数据流一点一点读取。
//设置请求体的输入流
[request setHTTPBodyStream:stream];
第十周
//自定义类型 在#import 下,@interface 上 定义以后,在本类中后者就可以代替前者使用
typedef int myInt;
typedef NSString String;
//定义一个block类型
typedef int (^myBlock)(int a,int b) ;
?
//block不能使用局部变量,可以使用全局变量,如果block中需要使用局部变量,需要在定义的变量前+ __block
//局部变量在block中只读。而且,是一次性赋值(把c的值copy到block中,以后c的值改变,并不会影响到block中的c)
//全局变量,__block变量,static变量,在block中引用的话,引用的是变量,而不是变量的值,也就是说,引用之后,变量发生改变的话,block中的值也会发生变化
//如果属于某个对象的block当中又使用到了这个对象,就会造成循环引用(对象和block的循环引用),导致最后对象释放不掉,所以,当属于某个对象的block使用这个对象时,应该再定义一个__block的指针指向这个对象,在block中使用__block指针。
//如果是ARC,用__weak
__block SecondVC *safeSelf = self;
self.block = ^{
safeSelf.view.backgroundColor = [UIColor redColor];
};
//全局的block(在栈内存中的block)需要对block块内局部变量的引用计数+1(块内全局变量不变)。
//某些情况下,不能使block的对象引用计数增加,那么在这个指针前+__block。
__block NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"123", nil];
//局部的 block 块内对象的引用计数均不变
self.block = ^{
[array addObject:@"222"];
[_array addObject:@"222"];
};
//GCD中使用线程队列实现多线程。
//我们可以在一个线程队列中加入一段代码,线程队列就会执行这个段代码。
//dispatch_queue_t 线程队列,
//dispatch_queue_create函数,创建一个新的线程队列,其中第一个参数是线程队列的标签(名字)。第二个参数是队列的类型。
//线程队列分为串行队列和并行队列,如果要创建串行队列,第二个参数写DISPATCH_QUEUE_SERIAL,并行队列写DISPATCH_QUEUE_CONCURRENT。
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
//虽然并行队列也可以创建,但是一般不去创建并行队列,而是找到系统自带的global并行队列使用。
dispatch_queue_t tQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//dispatch_sync在线程队列中同步执行一个block
//同步执行,相当于waitUntilDone,当前代码先停止,直到分线程的block中的代码执行完毕,当前线程才继续往下执行。
//异步执行,开启一个分线程后,当前线程不去等待分线程执行完毕,直接往下执行。
dispatch_async(concurrentQueue, ^{
NSLog(@"%@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1];
});
//dispatch_get_main_queue获得主线程队列,主线程只有一个,所以,主线程是串行队列。
dispatch_queue_t mainQueue = dispatch_get_main_queue();
//把刷新UI的代码放在主线程中执行
dispatch_async(mainQueue, ^{
_imageView.image = image;
});
});
//dispatch_suspend暂停一个线程队列,暂停之后,正在执行的block还会继续执行,这个block执行完之后,后面的block不会继续执行。 dispatch_suspend(_queue);
//dispatch_resume继续一个线程队列,继续之后,队列中的block会继续执行。
dispatch_resume(_queue);
//创建出来的线程队列用完之后需要release
dispatch_release(queue);
//dispatch_semaphore_t 线程信号量,dispatch_semaphore_create创建一个信号量,参数为初始信号量。
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
//dispatch_semaphore_signal给某个信号量发送一个信号,作用是使这个信号量+1.
dispatch_semaphore_signal(sem);
//dispatch_semaphore_wait等待信号量(等待信号量大于0),当信号量等于0时,当前线程会在这一行代码等待,直到sem信号的信号量大于0,当信号量大于0时,当前线程会对信号量-1,然后继续往下执行。
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
//设置一个信号量,信号量的值就是最大并发数。
dispatch_semaphore_t sema = dispatch_semaphore_create(10);
-使用semaphore设置并发队列的最大并发数-
//创建一个并发队列
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
//每当向队列中加入一个block时,先让线程等待,信号量足够时(大于0),线程执行,否则线程等待。
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
//code
//code
//code
//code
//当block执行完毕时,给信号量发送信号,使信号量+1
dispatch_semaphore_signal(sema);
});
//dispatch_after延迟执行一个block
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"3秒之前点击了button");
});
//NSOperationQueue,操作队列。
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//maxConcurrentOperationCount设置队列的最大并发数,当把最大并发数设置为1时,这个队列就相当于串行队列。
queue.maxConcurrentOperationCount = 10;
//addOperationWithBlock把一个block封装成NSOperation,然后把这个operation放进操作队列中执行。
[queue addOperationWithBlock:^{
NSLog(@"%d",[NSThread isMainThread]);
//currentQueue得到当前线程所在的操作队列。
NSOperationQueue *qu = [NSOperationQueue currentQueue];
//mainQueue得到主线程操作队列
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
}];
第十一周
//setApplicationIconBadgeNumber设置应用程序icon的角标
//申请推送权限,IOS8开始,需要申请推送权限,才能显示icon角标
[[UIApplication sharedApplication] registerUserNotificationSettings:nil];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:3];
//badgeValue属性,角标。
self.navigationController.tabBarItem.badgeValue = nil;
frame是相对于父类的坐标系,bounds 是相对于自己的坐标系
字符串的逆转
NSString *str = @"a,b,c,d";
NSMutableString *newStr = [[NSMutableString alloc]initWithCapacity:0];
@autoreleasepool {
for (int i = str.length-1; i>=0; i--)
{
[newStr appendString:[NSString stringWithFormat:@"%c",[str characterAtIndex:i]]];
}
}
NSLog(@"%@",newStr);
//在图片边缘添加一个像素的透明区域,去图片锯齿
CGRect imageRrect = CGRectMake(0, 0,_imageView.frame.size.width, _imageView.frame.size.height);
UIGraphicsBeginImageContext(imageRrect.size);
[_imageView.image drawInRect:CGRectMake(1,1,_imageView.frame.size.width-2,_imageView.frame.size.height-2)];
_imageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
?
2015.1.13
手势 touch时间 核心动画
/*iOS学习笔记之QuartzCore框架
iOS编程给用户视觉反馈其实都是通过QuartzCore框架来进行的,说白了,所有用户最终看到的显示界面都是图层合成的结果,而图层即是QuartzCore中的CALayer。
通常我们所说的视图即UIView,并不是直接显示在屏幕上,而是在创建视图对象的时候视图对象会自动创建一个层,而视图对象把要显示的东西绘制在层上,待到需要显示时硬件将所有的层拷贝,然后按Z轴的高低合成最终的显示结果。
CALayer本质上是一块包含一幅位图的缓冲区,由视图创建的层为隐式层,而手动创建的层称为显示层。
如果要在iOS上能够有良好的用户体验,动画的过渡效果是必不可少的,而所有的动画效果都是通过CAAnimation类的子类(CAAnimation是抽象类)来完成的。CAAnimation类的子类包括了 CAAnimationGroup,CAPropertyAnimation,CATransition,而CAPropertyAniamtion(同为抽象类)也衍生了CABasicAnimation和CAKeyframeAnimation。用UIView的animation实现的动画本质上也是通过CALayer来实现的,iOS系统中CALayer的很多属性都是隐含有动画效果的,如果不想要隐式动画或者想要显示动画效果,都可以通过CATransaction来设置是否显示动画效果。同时,在CATransaction内可同时修改多个属性,然后再一并同时渲染,另外CATransaction还是可嵌套的。
CABasicAnimation是一个最多只能有两个关键帧的动画,而 CAKeyframeAnimation除了可含有多个关键帧,而且还可以修改每个关键帧的速度。
CATransition能够为层提供移出以及移入屏幕的效果。苹果提供的所有动画类型在http://iphonedevwiki.net/index.php/CATransition这里有介绍,但是api只开放了其中的四种,当然你可以调用未公开的api,但是假如苹果以后出于安全还是什么原因调整接口的话,就不一定能用了,所以最好还是不要调用私有api,况且还有许多可以替代的方法,例如 @"flip”,@"pageCurl”这些type是属于未公开的,
//成为第一响应者
[self becomeFirstResponder];