1、修改光标颜色
UIView的属性tintColor用于修改光标颜色
2、图片拉伸
代码拉伸
//旧版本
@interface UIImage(UIImageDeprecated)
// use resizableImageWithCapInsets: and capInsets.
- (UIImage *)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWidth topCapHeight:(NSInteger)topCapHeight __TVOS_PROHIBITED;
@property(nonatomic,readonly) NSInteger leftCapWidth __TVOS_PROHIBITED; // default is 0. if non-zero, horiz. stretchable. right cap is calculated as width - leftCapWidth - 1
@property(nonatomic,readonly) NSInteger topCapHeight __TVOS_PROHIBITED; // default is 0. if non-zero, vert. stretchable. bottom cap is calculated as height - topCapWidth - 1
@end
leftCapWidth代表左侧需要保护的部位(自动计算左侧需要保护部分为width - leftCapWidth - 1)
topCapHeight代表顶部需要保护的部位(自动计算左侧需要保护部分为height - topCapHeight - 1)
保留中间的1个点进行拉伸
//新版本
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets NS_AVAILABLE_IOS(5_0); // create a resizable version of this image. the interior is tiled when drawn.
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode NS_AVAILABLE_IOS(6_0); // the interior is resized according to the resizingMode
capInsets代表上左下右四个方向需要保护的区域
拉伸区域可以根据需求定制
新特性(Assets)自动拉伸
(利用新特性拉伸图片,编译器会先自动确定一个拉伸区域和保护区域;如果图片是对称的,那么系统默认拉伸图片中心的一个点;如果不对称,系统默认会自动保护不对称区域,在此过程中还会避让圆角不被拉伸,总之,相当智能)
//1、在Assets.xcassets中选择要拉伸的图片 //2、选择窗口右上角图片属性 //3、在slicing->slices选择Horizontal and Vertical选项,表示水平和垂直方向都拉伸即可 //4、新特性会自动计算拉伸区域和需要保护的区域,也可以手动编辑
新特性拉伸操作方法1
![Uploading Snip20160225_6_823671.png . . .]新特性拉伸操作方法2
Snip20160225_6.png3、修改背景alph值而不影响子控件的alph,子控件不继承父控件的alph值
有时候我们需要修改控件的背景透明度,但是子控件默认
回继承父控件的透明度属性,此时可以这样干
self.backgroundColor = [[UIColor clearColor] colorWithAlphaComponent:0.1];
4、解决导航栏的标题不居中
//当导航栏的标题不居中,在上一页消失的时候将标题设为nil即可
5、坐标系转换
convertRect
和convertPoint
作为UIView转换坐标系的方法,是将view所在坐标系内(即以view的左上角为坐标原点(0,0))
的一块区域或者一个点的坐标
转换到目标坐标系内,这里的view
和区域以及点
是存在父子关系的。只能将父控件所在坐标系(即以父控件的左上角为坐标原点(0,0))内部的区域或者点
转换坐标系,否则会出现意想不到的错误。frame描述的是控件在其父控件坐标系内的位置和尺寸,同一个坐标系内的位置比较才是有意义的。
6、扩大UIButton的点击区域
要扩大UIButton的点击事件响应范围,只需要重写UIButton的hitTest方法
//将点击事件响应范围扩大到周边20个点
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGRect rect = self.frame;
//新的响应事件的区域
//这里的区域是在父控件坐标系内的
rect.origin.x -= 20;
rect.origin.y -= 20;
rect.size.height += 20 * 2;
rect.size.width += 20 * 2;
//将点转换到与响应事件的区域在同一个坐标系内
CGPoint p = [self convertPoint:point toView:self.superview];
//判断点是否在新的事件响应区域内
if (CGRectContainsPoint(rect, p))
{
return self;
}
else
{
return [super hitTest:point withEvent:event];
}
}
6、HitTest
1)将当前当前坐标系上的点转换到指定坐标系上的点
2)判断点不在目标坐标系上
3)如果点在目标坐标系上,且目标坐标系内存在多个控件,需要调用坐标的HitTest
找到最合适的控件;如果找不到这个更合适的View(或者没有子控件,因为只有自己)就返回自己,作为最终的事件接收者
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
//1、当按钮超出父控件的范围,使其可以响应事件
//1.1 将父控件相应点,转换到按钮内部坐标系
CGPoint cartButtonPoint = [self convertPoint:point toView:self.cartButton];
//1.2 判断转换后的点是否在按钮上
if ([self.cartButton pointInside:cartButtonPoint withEvent:event])
{
//1.3 转换后的点在按钮上,且按钮没有子控件可以遍历,返回按钮本身
return self.cartButton;
}
//2、当UITableView超出父控件的范围,使其可以响应事件
//2.1 将父控件相应点,转换到UITableView内部坐标系
CGPoint goodsListViewPoint = [self convertPoint:point toView:self.goodsListView];
//2.2 判断转换后的点是否在UITableView上
if ([self.goodsListView pointInside:goodsListViewPoint withEvent:event])
{
//2.3 转换后的点在UITableView上,且存在子控件,所以调用HitTest方法查找最合适的View响应事件
UIView *subView = [self.goodsListView hitTest:goodsListViewPoint withEvent:event];
//2.3 如果找到更合适的View返回即可,如果没有返回UITableView自响应事件
return subView ? subView : self.goodsListView;
}
//3、 其余没有特殊处理的子控件调用父类的HitTest方法找到最合适的View来响应事件
return [super hitTest:point withEvent:event];
}
6、在使用AFnetwotking的时候,报错提示一堆的二进制流数据并且以“text/html”结束,问题基本就在于你们服务端返回的二进制流的解析格式(text/html)不是常用的json,xml等,需要手动修改afnetworking源码,在框架内查找“text/json”字符串并参照添加不能解析的格式串“text/html”在后面,即可,记得要全部添加
7、在使用iOS原生扫码的时候奔溃在self.output.metadataObjectTypes(设置扫码类型)
,通常是权限为题。
8、设置标题栏
如果要同时改变导航栏标题和UITabBar对应的标题,使用self.title
如果单独改变导航栏标题建议使用self.navigationItem.title
如果导航控制器和UITabBarController都自定义了,建议使用self.navigationItem.title
最后,建议尽量使用self.navigationItem.title
设置标题。在没有特殊需要,我们尽量不需要迁一发动全身的代码,也是遵循低耦合的编码规范
9、UICollectionView cellForItematIndexpath返回为nil
在reloadData后调用 layoutIfNeeded
[collectionView reloadData];
[collectionView layoutIfNeeded];
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y > 200 - 64) {
CGFloat x = scrollView.contentOffset.x;
scrollView.contentOffset = CGPointMake(x, 200 - 64);
self.v.alpha = 1.0;
}
else if ((scrollView.contentOffset.y < 200 - 64))
{
if (scrollView.contentOffset.y > 0)
{
CGFloat alpha = (1.0 / (200 - 64)) * scrollView.contentOffset.y;
NSLog(@"%f==%f",alpha,scrollView.contentOffset.y);
self.v.alpha = alpha;
}
else
{
self.v.alpha = 0;
}
}
}
10、字典setValue
value值为空,导致奔溃
给NSMutableDictionary
添加一个分类实现setValue: forUndefinedKey:
方法
#import "NSMutableDictionary+ValueForNil.h"
@implementation NSMutableDictionary (ValueForNil)
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
}
@end
11、@dynamic和@synthesize
1、@dynamic 属性名称;//表示属性的setter和getter方法将会动态添加,不用手动实现
2、@synthesize 属性名称;//表示属性的setter和getter方法由编译器合成,(使用@property关键字的默认实现,不用显示的告知编译器)
3、在category中使用@property关键字编译器是不能自动合成setter和getter方法的,而且编译器不允许显示的使用@synthesize来合成setter和getter方法,因为category中的@property关键字并不生成默认的下划线成员变量,没有办法合成。
4、在category添加的属性是动态添加的,setter和getter方法页需要我们动态添加可以直接实现setXXX:和xxx方法,也可以使用class_addMethod来动态添加(推荐使用,可以减少不必要的重复代码,使用此方法,通常会配合dynamic关键字,以消除警告)
12、swift的xib在iOS8系统下的使用
在iOS8系统下使用xib的时候要格外小心,通常我们无论控制器是xib
还是纯代码只需要使通用的()创建控制器,但是iOS颠覆了这一切,如
果控制器使用xib,必须使用xxx(nibName: "", bundle: nil),否则xib
中的所有控件是不会创建,初始化的,如果过此时你将xib中的控件连
线到控制器的class中(默认的xib的连线属性都是!强解包的),就会报option变量强解包失败而奔溃
13、iOS和JSON串转换
无论OC还是swift不要使用NSJSONWritingPrettyPrinted会带有回车,服务器无法解析
//OC版
NSArray *params = @[@{@"name":@"小史",@"age":@"80"},
@{@"name":@"小史",@"age":@"80"},
@{@"name":@"小史",@"age":@"80"}];
NSData *data = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",string);
//Swift版
let data = try? JSONSerialization.data(withJSONObject: params!, options: [])
jsonString = String.init(data: data!, encoding: String.Encoding.utf8) ?? jsonString
print(jsonString)
14、线程保命使用Runloop
而不是strong
强引用
线程保命不能使用strong
强引用,线程一旦task
结束就会自动回收,指向线程的指针就会成为野指针,如果使用强引用指针去保命,在线程结束后去用强引用的指针去使用线程,直接野指针crash
,线程保命应该使用Runloop,可以参见AFNetworking中的异步实现,如果给线程保命,那么AFNetworking的异步回调将不可能回调,因为在一步回调之前,线程已经结束,线程结束线程中所有的task
将不会再被执行
15、关闭隐式动画
对非Root Layer的部分属性进行修改时,默认会自动产生一些动画效果,而这些属性称为Animatable
CATransaction.begin()
CATransaction.setDisableActions(true)
//图层CALayer操作
16、可变参数传递解析
1、可变参数传递使用
...
,注意在方法声明后添加宏NS_REQUIRES_NIL_TERMINATION(数组的创建等等就会用到)
,表示方法调用已nil
结束,因为可变参数的接收会用到C语言结构的遍历,已nil
结束帮助遍历结束
2、安全考虑指针操作,va_start(不包含启始元素)
和va_end
成对出现
3、可变参数接收的数据结构是一个栈,va_arg
指针将移动到下一个参数,上一个参数出栈
//声明
- (void)test:(id)arg1,...NS_REQUIRES_NIL_TERMINATION;
//实现
- (void)test:(id)arg1,...
{
va_list args;
va_start(args, arg1);
if (arg1)
{
id otherArg = nil;
NSLog(@"%@",arg1);
while (1)
{
otherArg = va_arg(args, id);
if (otherArg == nil)
{
break;
}
NSLog(@"%@",otherArg);
}
va_end(args);
}
}
17、隐藏导航栏,但是保留侧滑
//保留侧滑
self.navigationController.navigationBar.hidden = YES;
//不保留侧滑
self.navigationController.navigationBarHidden = YES;
18、使用快速构建数组的方法构建数组,必须确保数组的元素非空,非直接创建的数组最好不要使用快速构建的方法
19、微信授权
微信授权在sdk中有直接的接口,其实就是授权登录,授权的之前必须
20、pathforresource返回路径为nil
json,等一些资源文件需要在Build Phaeses->Copy Bundle Resource进行手动添加
21、UIImage旋转显示
self.idCardFrontImageView.image = [UIImage
imageWithCGImage:image.CGImage scale:1.0
orientation:UIImageOrientationLeft];
22、%和&
当集合容量是2的n次幂的时候,计算元素在集合的位置的时候
集合编号 % 集合容量 <=> 集合编号 & (集合容量 - 1)
未完待续。。。