1、在UIScorllView上添加UISlide,拖动slide的时候,scrollerview会跟着动,解决方案
在项目开发时遇到一个问题,我在UIViewController上面直接创建了一个UIScrollerView,把UIScrollerView作为一个子视图添加到了UIViewController,
又再UIScrollerView中添加了一个UISlider的组件,在手势滑动的过程中,很难滑动到UISlider这个控件,经常是滑动的时候UIScrollerView进行了滚动,
而UISlider这个控件没有滑动,让人很抓狂。
上网具体去了解了一下UIScrollerView的详解,终于彻底明白了问题出在哪里
下面引用一下前辈的总结,因为自己觉得没有他总结的详细
UIScrollView重载了hitTest方法,当手指touch的时候,UIScrollView会拦截所有event,然后等待150ms,在这段时间内,如果没有手指没有移动,当时间结束时,UIScrollView会发送tracking event到子视图上,并且自身不滑动。在时间结束前,手指发生了移动,那么UIScrollView就会进行滑动,从而取消发送tracking。
看来是UIScrollView的问题。直接拖动UISlider,此时touch时间在150ms以内,UIScrollView会认为是拖动自己,从而拦截了event,导致UISlider接受不到滑动的event。但是只要按住UISlider一会再拖动,此时此时touch时间超过150ms,因此滑动的event会发送到UISlider上。
期间试过几种方法,只有一种可行,就是重写UIScrollView的hitTest方法:当滑动UISlider时,使UIScrollView不可滑动。
但是又出现了一个问题,我的UIScrollerView是直接继承了UIScrollerView,在UIViewController中是无法重写的UIScrollerView的hitTest方法的,所以需要重新创建一个view,继承UIScrollerView,然后再重写上述方法,然后再导入UIViewController中就可以轻松实现了。
2、IOS 截屏模糊 的问题
情景: 遇到的分享的图片 很模糊。
那么首先去搜索下 在你的代码里面有没有遇到
用 UIGraphicsBeginImageContext(<#CGSize size#>) 这个方法。
解决:
如果有那么 截屏的图片肯定是模糊的,因为在iOS7 的分辨率会改为另外一种代替的方法
就是它 :
UIGraphicsBeginImageContextWithOptions(<#CGSize size#>, <#BOOL opaque#>, <#CGFloat scale#>)
代码如下:
-(UIImage *)captureImageFromViewLow:(UIView *)orgView {
//获取指定View的图片
UIGraphicsBeginImageContextWithOptions(orgView.bounds.size, YES, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.navigationController.view.layer renderInContext:context];//如果截屏中不想带有导航条的话这行代码改为[orgView.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
3、侧滑删除
NSIndexPath *_indexPath;//判断删除的是那个cell(侧滑删除cell)
NSArray *_indexPathArr;
#pragma mark -- 侧滑删除
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self presentViewController:_alert animated:YES completion:nil];
MessageModel *model = _dataSource[indexPath.section];
_indexPath = indexPath;
_indexPathArr = [NSArray arrayWithObjects:indexPath, nil];
_studentId = model.studentId;
_messageId = model.messageId;
}
}
#pragma mark 给删除命名为中文的
- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath
{
return @"删除";
}
-(void)createUIAlertController
{
_alert = [UIAlertController alertControllerWithTitle:@"删除后将不会恢复,是否确认删除" message:nil preferredStyle:UIAlertControllerStyleAlert];
[_alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSString *str = [NSString stringWithFormat:@"%@api/user/deleteMessage.do?messageId=%@&studentId=%@",baseUrl,_messageId,_studentId];
[AFNet JSONDataWithUrl:str success:^(id json) {
NSDictionary *dic = [NullToNone nullDic:json];
NSString *str = dic[@"msg"];
if ([str isEqualToString:@"success"]) {
[dataArray removeObjectAtIndex:_indexPath.row];
//从tableview中删除指定行
[self.tableV deleteRowsAtIndexPaths:_indexPathArr withRowAnimation:UITableViewRowAnimationFade];
}else{
[SVProgressHUD showErrorWithStatus:@"删除失败" duration:1];
return ;
}
} fail:^{
}];
}]];
[_alert addAction:[UIAlertAction actionWithTitle:@"取消"style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {[self.tableView reloadRowsAtIndexPaths:_indexPathArr withRowAnimation:UITableViewRowAnimationFade];
}]];}
4、AFNetworking
https://www.baidu.com/baidu?tn=monline_3_dg&ie=utf-8&wd=afnetworking
请求头:我们执行网络请求的时候给服务器发送的包头信息(包括你当前使用什么设备请求的、当前设备信息等等)
请求正文:上面例子网址的问号之后的都是请求正文
GET:请求一些简单的数据,一般都是明文显示,携带数据量小
POST:处理复杂的业务,比如上传图片,加密参数等;与GET不同地方,1,并不是明文请求,请求正文被加载到了数据当中,从浏览器里很少能看到post请求所携带的参数;2,可以携带更多的参数
断点下载:1,断点下载需要服务器支持; 2,在执行请求时,我们需要设定Request fields上的Range参数才能生效
5、原生APP——优缺点
优点:1、运行效率高2、可调用各种设备资源
缺点:1、人力成本高2、发布速度慢3、更新版本的问题(用户就是不更新)4、实现图文混排功能有各种坑(很麻烦)
6、WEBAPP核心思路
HTML5 css3 js 开发完了之后打包(用phoneGap等打包)
7、代理
委托方:1.声明协议2.声明代理3.定义代理方法
.h文件里:
.m文件里:
代理方:1、遵守协议2.把自己设为代理3.实现代理方法
遵守协议sendDataAttributes;
把自己设为代理DataNameListController *dataName = [[DataNameListController alloc]init];
dataName.sendDataAttributesDelegate = self;
实现代理方法
-(void)sendDataAttributes:(NSArray *)array{}
8、懒加载及self.和下划线区别
a.懒加载:被声明为属性的成员,在ios5之前需要使用编译器指令@synthesize告诉编译器帮助生成属性的getter,setter方法。之后会默认生成。编译器在生成getter,setter方法时先检查有没有自定义getter,setter方法,如果有则使用自定义的,没有才生成。
懒加载就是重写属性的getter方法,然后加一个判断,为空则赋值,不为空则返回。代码如下:
没有懒加载的情况下,如果想给一个数组_dataSource赋值,需要在viewDidload里面写类似于
_dataSource = @[@"123",@"qe",@"123",@"ad",@"123",@"adasda"];
这就出现了一个问题,当然也不称得上问题,只是代码需要优化而已,因为当_dataSource需不需要的时候你都要给_dataSource初始化并赋值。这就占用了没必要的内存。如果你只想在用到_dataSource的时候才给它初始化并赋值的时候,这时你就用到了懒加载。
示例代码:
- (void)viewDidLoad {
[super viewDidLoad];
}
-(NSArray *)dataSource{
if(!_dataSource){
_dataSource = @[@"123",@"qe",@"123",@"ad",@"123",@"adasda"];
}
return _dataSource;
}
当需要用到_dataSource的时候,就会调用[self dataSource]的方法(即getter方法)。注意:需要注意在getter方法里切勿使用self.dataSource,因为self.dataSource会调用getter方法,造成死循环。
总结:懒加载即用到时方去加载对象。
b.self.mtest和_mtest的区别
在第一次使用时由于没注意到两者的区别,在setter方法中调用self.mtest,结果导致了setter方法的循环调用。写法如下:
导致原因是,self.mtest会调用属性的setter方法,触发懒加载,但是_mtest只是访问一个局部变量。
9、assign,retain,copy的区别
解释一:
一、assign属性
当数据类型为int、float等原生类型时,可以使用assign,否则可能导致内存泄露。例如当使用malloc分配了一块内存,并把它的地址赋值给了指针a,后来如果希望指针b也共享这块内存,于是讲a赋值给(assgin)b。这时就用到了assgin,此时a和b指向同一块内存。但是现在问题出现了,当a不再需要这块内存时,能都直接释放呢?肯定是不能的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候引起程序crash掉。
二、retain属性
retain属性就是为了解决上述问题而提出的,使用了引用计数(reference counting),还是上面那个例子,我们给那块内存设一个引用计数,当内存呗分配并且赋值给a时,引用计数是1.当把a赋值给b时引用计数增加到2.这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1.当引用计数变为0的时候,代表该内存不再被任何指针所引用,系统可以直接释放掉。此时系统自动调用dealloc函数,内存被回收。(自己想了个🌰:你在小区有一个车位,平时你把自己的车停那,你弟弟这时候也想用你的车位,于是你就retain了一下,把这个车位使用人数名字上又增加了一位(引用计数加一),然后你弟和你都可以共用这一个车位。当你或者你弟弟其中一个人不想用的时候(引用计数减一),不想用的那个人能直接把车位上交给小区管理人员吗(内存释放)?不可以!因为你不用了,另外一个还在用,所以还不能把车位上交给小区管理人员,当你俩都不想用了的话就可以把车位上交给物业了)
三、copy属性
copy是你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。
解释二:
举个例子:
NSString *str = [[NSString alloc] initWithString:@'abc'];
上面一段代码会执行以下两个动作:
1 在堆上分配一段内存用来存储@'abc' ,比如:内存地址为0X1111 内容为 'abc'
2 在栈上分配一段内存用来存储str,比如:地址为0XAAAA 内容自然为0X1111
下面分别看下(assign,retain,copy):
1.assign的情况:NSString *newStr = [str assign];
此时newStr和str完全相同,地址都是0XAAAA ,内容为0X1111 ,即newStr只是str的别名,对任何一个操作就等于对另一个操作。因此retainCount不需要增加.
2.retain的情况:NSString * newStr = [str retain];
此时newStr的地址不再为0XAAAA,可能为0XAABB,但是内容依然为0X1111.因此newStr和str都可以管理'abc'所在的内存。因此 retainCount需要增加1.
3.copy的情况:NSString * newStr = [str copy];
此时会在堆上重新开辟一段内存存放@‘abc',比如0X1122,内容为@'abc,同时会在栈上为newStr分配空间,比如地址:0XAACC,内容为0X1122,因此retainCount增加1供newStr来管理0X1122这段内存.
NSString为何要用copy?而不是strong?
strong和retain同义, weak和assign同义, 为什么要采用这种说法, 似乎是ARC出现后为了消除引用计数的观念而采用的做法. 至于为什么要用copy, 由于纯NSString是只读的, 所以strong和copy的结果一样,据stackOverflow上的说法,是为了防止mutable string被无意中修改, NSMutableString是NSString的子类, 因此NSString指针可以持有NSMutableString对象.
很简单,假如有一个NSMutableString,现在用他给一个retain修饰 NSString赋值,那么只是将NSString指向了NSMutableString所指向的位置,并对NSMUtbaleString计数器加一,此时,如果对NSMutableString进行修改,也会导致NSString的值修改,原则上这是不允许的. 如果是copy修饰的NSString对象,在用NSMutableString给他赋值时,会进行深拷贝,及把内容也给拷贝了一份,两者指向不同的位置,即使改变了NSMutableString的值,NSString的值也不会改变.
所以用copy是为了安全,防止NSMutableString赋值给NSString时,前者修改引起后者值变化而用的.
10、view的frame和bounds的区别
参考这个哥们写的:http://blog.csdn.net/mad1989/article/details/8711697
11、int 和NSInteger的区别
原来在苹果的api实现中,NSInteger是一个封装,它会识别当前操作系统的位数,自动返回最大的类型。
当需要使用int类型的变量的时候,可以像写C的程序一样,用int,也可以用NSInteger,但更推荐使用NSInteger,因为这样就不用考虑设备是32位的还是64位的。
定义的代码类似于下:
#if __LP64__ || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif
12、NSInteger和NSNumber 的区别
NSNumber是NSValue的子类,一般情况下,其功能就是使得数字能够添加到类似NSArray或者NSSet数据集合中,NSNumber不仅仅能够表示NSInteger类型的整形数,还可以表示浮点数。
NSInteger a = 1;
NSMutableArray *arr = [[NSMutableArray alloc] init];
//[arr addObject:a]; // 程序奔溃,不能够将整形添加到数组中
NSNumber *aNum = [NSNumber numberWithInt:a];
[arr addObject:aNum]; // 转换为NSNumber后就OK了
NSNumber表示数字类,浮点,整形,长整形,无符号等,NSIntege只是NSNumber能表示的一种数字类而已。
13、Objective-C中@property的所有属性详解
1,assign :
简单赋值,不更改索引计数
假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a 和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候会引起程序crash掉
应用场合:
对基础数据类型 (例如NSInteger,CGFloat)和C数据类型(int, float, double, char, 等)
适用简单数据类型
2,retain:
与strong相对应,使用了引用计数,retain+1,release -1;当引用 计数为0时,dealloc会被调用,内存被释放
3,copy:
用于非共享内存时,每个指针有自己的内存空间
4,atomic//默认属性
A,当一个变量声明为atomic时,意味着在多线程中只能有一个线程能对它进行访问
B,当一个变量声明为atomic时,该变量为线程安全型,但是会影响访问速度,
C,当一个变量声明为atomic时,在非ARC编译环境下,需要设置访问锁来保证对该变量进行正确的get/set
5,nonatomic
A, 当一个变量声明为nonatomic时,意味着多个线程可以同时对其进行访问
B, 当一个变量声明为nonatomic时,它是非线程安全型,访问速度快;
C, 当一个变量声明为nonatomic时,当两个不同的线程对其访问时,容易失控。
总结:atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。加了atomic,setter函数会变成下面这样:
if (property != newValue) {
[property release];
property = [newValue retain];
}
6.strong://ARC中默认属性,等于非ARC中的retain
与retain相对应,
应用场景:
strong属性用于ARC中
@property (strong,nonatomic) ViewController *viewController;
7,weak:
与assign 相对应,
应用场景:
用于IBOutlets,如,UIViewController的子类,即一般的控件。
@property (weak, nonatomic) IBOutlet UIButton *myButton;
strong与weak的区别举例:
前提:
我们把要用strong或者weak的对象比作一只风筝,风筝想挣脱线的束缚,自由飞翔去,如果此时有一根线,那么这只风筝就挣脱不了
过程分析
strong属性的变量:
当我们把指向一只风筝的变量声明为strong时,此时,你就拥有控制这只风筝的线,假如此时有五个人同时控制这只风筝(即这只风筝对象有三个strong类型的变量指向它),那么只有一种情况,这只风筝才会挣脱掉线的束缚:这三个人都放掉手中的线,(release掉)
weak属性的变量:
当我们把指向一只风筝的变量声明为weak时,此时,就像站在旁边看风筝的观众们一样,当上面的三个人还握着手中的线时,他们只能看到风筝,并不能控制它,他们能做的只能是用手指指向风筝,并大喊,“看,那只风筝飞得真高!”,然而,当上面的三个人把手中的线都放掉时,此时,风筝飞走了,看不见了,不管有再多的观众,他们再也看不到风筝了,这个故事告诉我们一个道理:当strong类型的指针被释放掉之后,所有的指向同一个对象的weak指针都会被清零。
8,readonly
只有get方法,没有set方法
9,readwrite//默认属性
有get/set方法
10,unsafe_unretauined
用在ARC编译环境下,在此环境下,与assign相似。它只是告诉ARC如何正确地调用声明为unsafe_unretauined变量的retain和release
14、线程安全
比如一个 ArrayList 类,在添加一个元素的时候,它可能会有两步来完成:1. 在 Items[Size] 的位置存放此元素;2. 增大 Size 的值。
在单线程运行的情况下,如果 Size = 0,添加一个元素后,此元素在位置 0,而且 Size=1;
而如果是在多线程情况下,比如有两个线程,线程 A 先将元素1存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B向此 ArrayList 添加元素2,因为此时 Size 仍然等于 0 (注意,我们假设的是添加一个元素是要两个步骤,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增加 Size 的值,结果Size等于2。
那好,我们来看看 ArrayList 的情况,期望的元素应该有2个,而实际只有一个元素,造成丢失元素,而且Size 等于 2。这就是“线程不安全”了。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步(同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。),否则的话就可能影响线程安全。
15、关于nil和 null和NSNull的区别及相关问题
nil -> Null-pointer to objective- c object
NIL -> Null-pointer to objective- c class
null-> null pointer to primitive type or absence of data.
1.nil
指向一个对象的指针为空
在Objective-C中用于id类型的对象
NSString *name = nil;
NSURL *url = nil;
id object = nil;
2.Nil
指向一个类的指针为空
在Objective-C中用于Class类型的对象
Class aClass = Nil;
Clsss bClass = [NSURL class];
3.NULL
指向C类型的指针为空
多用于如下例子:
int *pInt = NULL;
char *chChar= NULL;
struct stStruct = NULL;
4.NSNull
在Objective-C中是一个类,只是名字中有个Null,NSNull有 + (NSNull *)null; 单例方法,多用于集合(NSArray,NSDictionary)中值为空的对象
NSArray *array = [NSArray arrayWithObjects:
[[NSObject alloc] init],
[NSNull null],
@"aaa",
nil,
[[NSObject alloc] init],
[[NSObject alloc] init], nil];
NSLog(@"%ld", array.count); // 输出 3,NSArray以nil结尾
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
@"Object0", @"Key0",
@"Object1", @"Key1",
nil, @"Key-nil"
@"Object2", @"Key2",
nil];
NSLog(@"%@", dictionary); // 输出2个key-value,NSDictionary也是以nil结尾
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] init];
[mutableDictionary setObject:nil forKey:@"Key-nil"]; // 会引起Crash
[mutableDictionary setObject:[NSNull null] forKey:@"Key-nil"]; // 不会引起Crash
所以在使用时,如下方法是比较安全的
[mutableDictionary setObject:(nil == value ? [NSNull null] : value)
forKey:@"Key"];
16、iOS开发网络篇-HTTP协议
说明:apache tomcat服务器必须占用8080端口
一、URL
1.基本介绍
URL的全称是Uniform Resource Locator(统一资源定位符)
通过1个URL,能找到互联网上唯一的1个资源
URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL
2.URL中常见的协议
(1)HTTP
超文本传输协议,访问的是远程的网络资源,格式是http://
http协议是在网络开发中最常用的协议
(2)file
访问的是本地计算机上的资源,格式是file://(不用加主机地址)
(3)mailto
访问的是电子邮件地址,格式是mailto:
(4)FTP
访问的是共享主机的文件资源,格式是ftp://
二、HTTP协议
1.HTTP协议简介
不管是移动客户端还是PC端,访问远程的网络资源经常使用HTTP协议
访问百度主页:http://www.baidu.com
获得新浪的微博数据
获得大众点评的团购数据
2.HTTP协议的作用
HTTP的全称是Hypertext Transfer Protocol,超文本传输协议
(1)规定客户端和服务器之间的数据传输格式
(2)让客户端和服务器能有效地进行数据沟通
3.为什么选择使用HTTP?
(1)简单快速 因为HTTP协议简单,所以HTTP服务器的程序规模小,因而通信速度很快
(2)灵活 HTTP允许传输任意类型的数据
(3)HTTP 0.9和1.0使用非持续连接 限制每次连接只处理一个请求,服务器对客户端的请求做出响应后,马上断开连接,这种方式可以节省传输时间
4.HTTP的通信过程
要想使用HTTP协议向服务器索取数据,得先了解HTTP通信的完整过程
完整的http通信可以分为2大步骤
(1)请求:客户端向服务器索要数据
(2)响应:服务器返回客户端相应的数据
三、HTTP通信过程 - 请求和响应
1.HTTP通信过程 - 请求
HTTP协议规定:1个完整的由客户端发给服务器的HTTP请求中包含以下内容
请求行:包含了请求方法、请求资源路径、HTTP协议版本
GET /MJServer/resources/images/1.jpg HTTP/1.1
请求头:包含了对客户端的环境描述、客户端请求的主机地址等信息
Host: 192.168.1.105:8080 // 客户端想访问的服务器主机地址
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9) Firefox/30.0// 客户端的类型,客户端的软件环境
Accept: text/html, */*// 客户端所能接收的数据类型
Accept-Language: zh-cn // 客户端的语言环境
Accept-Encoding: gzip // 客户端支持的数据压缩格式
请求体:客户端发给服务器的具体数据,比如文件数据
2.HTTP通信过程 - 响应
客户端向服务器发送请求,服务器应当做出响应,即返回数据给客户端
HTTP协议规定:1个完整的HTTP响应中包含以下内容:
状态行:包含了HTTP协议版本、状态码、状态英文名称
HTTP/1.1 200 OK
响应头:包含了对服务器的描述、对返回数据的描述
Server: Apache-Coyote/1.1 // 服务器的类型
Content-Type: image/jpeg // 返回数据的类型
Content-Length: 56811 // 返回数据的长度
Date: Mon, 23 Jun 2014 12:54:52 GMT // 响应的时间
实体内容:服务器返回给客户端的具体数据,比如文件数据
3.补充:推荐工具firebug-1.12.5-fx.xpi
虫子的作用:拦截所有的http请求。
4.常见的响应状态码
四、发送HTTP请求的方法
1.简单说明
在HTTP/1.1协议中,定义了8种发送http请求的方法
GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
根据HTTP协议的设计初衷,不同的方法对资源有不同的操作方式
PUT :增
DELETE :删
POST:改
GET:查
提示:最常用的是GET和POST(实际上GET和POST都能办到增删改查)
2.get和post请求
要想使用GET和POST请求跟服务器进行交互,得先了解一个概念:参数就是传递给服务器的具体数据,比如登录时的帐号、密码。
GET和POST对比:GET和POST的主要区别表现在数据传递上。
GET
在请求URL后面以?的形式跟上发给服务器的参数,多个参数之间用&隔开,比如http://ww.test.com/login?username=123&pwd=234&type=JSON
注意:由于浏览器和服务器对URL长度有限制,因此在URL后面附带的参数是有限制的,通常不能超过1KB
POST
发给服务器的参数全部放在请求体中
理论上,POST传递的数据量没有限制(具体还得看服务器的处理能力)
3.GET和POST的选择
选择GET和POST的建议
(1)如果要传递大量数据,比如文件上传,只能用POST请求
(2)GET的安全性比POST要差些,如果包含机密\敏感信息,建议用POST
(3)如果仅仅是索取数据(数据查询),建议使用GET
(4)如果是增加、修改、删除数据,建议使用POST
4.iOS中发送HTTP请求的方案
在iOS中,常见的发送HTTP请求(GET和POST)的解决方案有
(1)苹果原生(自带)
NSURLConnection:用法简单,最古老最经典最直接的一种方案
NSURLSession:iOS 7新出的技术,功能比NSURLConnection更加强大
CFNetwork:NSURL*的底层,纯C语言
(2)第三方框架
ASIHttpRequest:外号“HTTP终结者”,功能极其强大,可惜早已停止更新
AFNetworking:简单易用,提供了基本够用的常用功能
建议:
为了提高开发效率,企业开发用的基本是第三方框架
5.ASI和AFN架构对比
说明:AFN基于NSURL,ASI基于CFHTTP,ASI的性能更好一些。
17、堆和栈
参考:http://my.oschina.net/openlab/blog/195068
18、计算缓存
- (long long)checkCache {
NSFileManager *fileManager=[NSFileManager defaultManager];
float folderSize;
if ([fileManager fileExistsAtPath:EBCACHE]) {
NSArray *childerFiles=[fileManager subpathsAtPath:EBCACHE];
for (NSString *fileName in childerFiles) {
NSString *absolutePath=[EBCACHE stringByAppendingPathComponent:fileName];
long long size=[fileManager attributesOfItemAtPath:absolutePath error:nil].fileSize;
folderSize += size;
}
folderSize+=[[EMSDImageCache sharedImageCache] getSize];
return folderSize;
}
return 0;
}
清除缓存:
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"缓存清除"message:@"确定清除缓存?"delegate:self cancelButtonTitle:@"取消"otherButtonTitles:@"确定",nil];
[alertView show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex ==1) {
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:EBCACHE error:nil];
}
}
备注:#define EBCACHE [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES) objectAtIndex:0]
19.各种xcode版本下载(官网):https://developer.apple.com/download/more/
20.设置状态栏字体颜色分两步:①,在appdelegate.m里设置
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];②,在plist文件里添加白名单:View controller-based status bar appearance,BOOL值为NO。
21.present到指定界面之后可以实现push的代码:
LoginViewController *login = [[LoginViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:login];
然后再present,present到指定界面(此处为Login界面)之后,Login界面就可以push了
[self.navigationController presentModalViewController:nav animated:YES];
22.隐藏导航栏下面的黑线
ios 找出导航栏下面的黑线(可隐藏,改变样式等)
根据UI的设计,navigationbar需要跟界面一体化,但是下面这根黑线是比较烦的问题,可能界面一需要隐藏,界面二就要出现,也可能需要改变粗细之类的,又因为navigationbar会影响接下来的推栈,所以需要做一点小改动.
方法1:直接隐藏:
//在页面出现的时候就将黑线隐藏起来
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:[UIImage new]];
}
//在页面消失的时候就让navigationbar还原样式
-(void)viewWillDisappear:(BOOL)animated{
[self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self.navigationController.navigationBar setShadowImage:nil];
}
这个方法唯一的不好就是会影响导航栏的translucent(透明)属性
方法2:找出黑线,再做处理:
//通过一个方法来找到这个黑线(findHairlineImageViewUnder):
- (UIImageView *)findHairlineImageViewUnder:(UIView *)view {
if ([view isKindOfClass:UIImageView.class] && view.bounds.size.height <= 1.0) {
return (UIImageView *)view;
}
for (UIView *subview in view.subviews) {
UIImageView *imageView = [self findHairlineImageViewUnder:subview];
if (imageView) {
return imageView;
}
}
return nil;
}
//再定义一个imageview来等同于这个黑线
UIImageView *navBarHairlineImageView;
navBarHairlineImageView = [self findHairlineImageViewUnder:self.navigationController.navigationBar];
同样的在界面出现时候开启隐藏
-(void)viewWillAppear:(BOOL)animated
{
navBarHairlineImageView.hidden = YES;
}
//在页面消失的时候就让出现
-(void)viewWillDisappear:(BOOL)animated
{
navBarHairlineImageView.hidden = NO;
}
如果想要做一些更好的处理,比如说改变粗细,颜色之类的也在界面出现的时候写就行了.
推荐使用第二种方法,因为整个项目都在使用导航栏推栈,出栈,很可能因为改变了样式,导致后面的属性混乱起来.
23.延时执行方法:
[self performSelector:@selector(hiddenControlView) withObject:nil afterDelay:3];//延时3s执行
[NSObject cancelPreviousPerformRequestsWithTarget:self];//取消延时执行
24、监听屏幕是否旋转
在viewdidload里面添加通知:[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
//通知方法:
- (void)statusBarOrientationChange:(NSNotification *)notification
{
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationLandscapeRight) // home键靠右
{
}
if (orientation ==UIInterfaceOrientationLandscapeLeft) // home键靠左
{
}
if (orientation == UIInterfaceOrientationPortrait)
{
}
if (orientation == UIInterfaceOrientationPortraitUpsideDown)
{
}
}
25.
编码:
- (NSString *)stringByAd
dingPercentE
scapesUsingEncoding:(NSStringEncoding)encoding
解码:- (NSString *)stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
26.调起打电话
NSMutableString * str=[[NSMutableString alloc] initWithFormat:@"telprompt://%@",@"xxxxx"];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:str]];
27.将图片保存到相册
UIImage *imgJPeg = [UIImage imageWithData:dJpeg];//建立UIIMage为jpeg格式
UIImageWriteToSavedPhotosAlbum(imgJpeg,nil,nil,nil);//保存到相册
28.生成随机数
Objective-C有个更方便的随机数函数arc4random_uniform(x),可以用来产生0~(x-1)范围内的随机数,不需要再进行取模运算。如果要生成1~x的随机数,可以这么写:arc4random_uniform(x)+1。
29.cocoapods使用教程(2017-01-17)(前提:已经安装cocoapods。简单粗暴,以下所添加的第三方AFNetworking只是举例,具体按照自己需要添加)
30.label自适应高度
#pragma mark ------ Lable自适应的方法1
-(CGRect)rectWidthAndHeightWithStr:(NSString *)str AndFont:(CGFloat)fontFloat
{
CGRect fcRect = [str boundingRectWithSize:CGSizeMake(600*WidthScale, 1000*HeightScale) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontFloat]} context:nil];
return fcRect;
}
#pragma mark ------ Lable自适应的方法2(更精确点)
- (CGRect)setupLabel:(UILabel *)textLabel withString:(NSString *)str andFont:(CGFloat)fontFloat {
//准备工作
textLabel.font = [UIFont systemFontOfSize:fontFloat];
textLabel.numberOfLines = 0;//根据最大行数需求来设置
textLabel.lineBreakMode = NSLineBreakByTruncatingTail;
CGSize maximumLabelSize = CGSizeMake(ScreenWidth-100, 9999);//labelsize的最大值
//关键语句
CGSize expectSize = [textLabel sizeThatFits:maximumLabelSize];
//别忘了把frame给回label,如果用xib加了约束的话可以只改一个约束的值
// textLabel.frame = CGRectMake(20, 70, expectSize.width, expectSize.height);
CGRect rect = CGRectMake(20, 70, expectSize.width+20, expectSize.height);
return rect;
}
31.苹果真机测试sdk文件路径:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
32.获取当前app版本号
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
// app版本号
NSString *app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];
33.推送消息的机制:
从上图我们可以看到:
1、应用程序注册消息推送。
2、iOS从APNS Server获取device token,应用程序接收device token。
3、应用程序将device token发送给PUSH服务端程序。
4、服务端程序向APNS服务发送消息。
5、APNS服务将消息发送给iPhone应用程序。
34.打印工程中的方法名
NSLog(@"%s",__FUNCTION__);
35.自适应一段文字(str)的高度
CGRect frame =[str boundingRectWithSize:CGSizeMake(SCREENW-70, MAXFLOAT) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:FONTSIZE]} context:nil];
CGSize textSize =frame.size;
其中MAXFLOAT为0x1.fffffep+127f,float类型(float的最大值)
38.application:application openURL: sourceApplication: annotation: 方法不执行
39.Archive的时候报错:
我们的开发者账号是企业开发账号,刚开始打包的时候报了上面的警告,以为是证书有问题(毕竟菜鸟,不知道什么原因,只能根据他们描述的错误猜一猜),但是用同一台电脑打包其他项目是可以的,所以排除证书问题;接着就可能是配置文件的问题,刚开始只配置了
但是这样并不可以,后来把图二和图三也配置了之后再打包就可以了;
40、self.tableView.tableFooterView = [[UIView alloc]init];//防止没内容的空cell下划线出现
41、手机内APP相互跳转
app1跳转到app2:①首先在app2里的info里点击URL Types,然后添加一个URL Schemes,URL Schemes的名字可以任意;②在app1的info.plist文件里LSApplicationQueriesSchemes
下添加一个string类型的item,名字为第一步给app2添加的那个URL Schemes的名字;③在app1中需要跳转的地方添加代码:
NSString *requestUrlString = @"app2添加的那个URL Schemes的名字://";
NSURL *requestUrl = [NSURL URLWithString: requestUrlString];
if([[UIApplication sharedApplication] canOpenURL:requestUrl]) {
[[UIApplication sharedApplication] openURL:requestUrl];
}