1.tableview的底部灰线延长到边:
//方法一:(iOS8以上)
self.tableView,separatorInset = UIEdgeInsetsZero;//清除tableView分割线内边距
cell的初始化方法里写: self.layoutMargins = UIEdgeInsetsZero;//清空cell的约束边缘
//方法二:
self.tableView.separatorStyle= UITableViewCellSeparatorStyleNone;//取消tableview的分割线
self.tableView.backgroundColor = [UIColor lightGrayColor];//设置tableView的背景色(=cell的背景色)
- (void)setFrame:(CGRect)frame{//cell 重写setFrame方法
frame.size.height-=1;
// 才是真正去给cell赋值
[super setFrame:frame];
}
2.cell圆角图片优化(剪切图片)
[_iconView sd_setImageWithURL:[NSURL URLWithString:item.image_list]placeholderImage:[UIImageimageNamed:@"defaultUserIcon"]options:SDWebImageCacheMemoryOnlycompleted:^(UIImage*image,NSError*error,SDImageCacheTypecacheType,NSURL*imageURL) {
// 1.开启图形上下文
// 比例因素:当前点与像素比例
UIGraphicsBeginImageContextWithOptions(image.size,NO,0);
// 2.描述裁剪区域
UIBezierPath*path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0, image.size.width, image.size.height)];
// 3.设置裁剪区域;
[path addClip];
// 4.画图片
[image drawAtPoint:CGPointZero];
// 5.取出图片
image =UIGraphicsGetImageFromCurrentImageContext();
// 6.关闭上下文
UIGraphicsEndImageContext();
_iconView.image= image;
}];
1. [[UIColor whiteColor]colorWithAlphaComponent:0.5]
2 // scrollView 默认内间距向下64,它上面的控件自动在y=64的位置
3. // 按钮里面的属性控件是懒加载的,只有设置相关属性才会创建
4. 加载三方bundle里的图片,需要加上bundle的文件名,格式:bundle文件名/图片名, 比如[UIImage imageName:@“SVProgressHUD.bundle/error”]
5. 自定义构造方法:
@property int age;
@property NSString *name;
//自定义构造方法 在初始化的时候为属性"年龄"和"姓名"赋值
- (instancetype)initWithAge:(int)age andName:(NSString *)name;
实现
// 实现自定义构造函数 在初始化的时候为属性赋值
- (id)initWithAge:(int)age andName:(NSString *)name
{
if (self = [super init]) {
_age = age;
_name = name;
}
return self;
}
6.
//标题按钮
BDJTitleButton* firstTitleButton = self.titlesView.subviews.firstObject;
titleUnderline.backgroundColor =[firstTitleButton titleColorForState:UIControlStateSelected];//下划线取button选中时的颜色
7. iOS里是控件准备显示的时候才去计算控件尺寸
8. self.tableView.contentInset = UIEdgeInsetMake(40,0,0,0);//设置内边距,不设置默认内边距64
9. //加载xib控件
UIView*testView = [[NSBundle mainBundle]loadNibNamed:@"TestView" owner:nil options:nil].firstObject;
[self.viewaddSubview:testView];
10. Xib 编译后会变成 Nib, bundle是放一下不需要编译的资源,bundle一般是放图片
11. cell的全屏穿透 `
self.tableView.contentInset= UIEdgeInsetsMake(64, 0, 49, 0);
12. 普通的UIViewController 的默认frame 是 {{0,0},{375,667}}
TableViewController的默认 frame 是 {{0,20},{375,647}} //这20 是状态栏的高度
13. ViewWithTag 递归查找(包括自己),也就说如果当前view也包含这个tag值,就不会采用子View的tag值对应的对象,所以要小心tag为0的情况
14.tableView的重要特性分析:
frame.size.height tableView自身的高度
contentSize.height所有内容的高度,内容: 1.有cell 2.没有contentInset 3.有tableHeaderView、tableFooterView
contentOffset.y == frame顶部和contentSize顶部 的差值(相减后的值)
也就是说:
contentInset: 在内容周围增加额外的间距(内边距),始终会粘着内容;
contentOffset:内容距离frame矩形框,偏移了多少;
有没有内边距跟contentOffset和 contentSize没关系;
15. frame : 是以父控件内容的左上角为坐标原点(0,0)
bounds: 是以自己的内容左上角x,y距离本身矩形框的x,y
16. view用到的时候再创建,//所以让他在点击标题按钮的时候再创建
/**
* 添加第index个子控制器的view到scrollView中
*/
- (void)addChildVcViewIntoScrollView:(NSUInteger)index
{
UIViewController *childVc = self.childViewControllers[index];
// 如果view已经被加载过,就直接返回
if(childVc.isViewLoaded)return;
//取出index位置对应的子控制器view
UIView*childVcView = childVc.view;
//设置子控制器view的frame
CGFloat scrollViewW = self.scrollView.kris_width;
childVcView.frame=CGRectMake(index * scrollViewW, 0, scrollViewW,self.scrollView.kris_height);
//添加子控制器的view到scrollView中
[self.scrollViewaddSubview:childVcView];
}
17. 状态栏盖在Window上面
18. [UIApplication sharedApplication].delegate; 就是APPDelegate的self
19. //让Appledelegate成为tabBar的代理,防止跳转其它界面被销毁,因为Applegate会一直存在,监听点击事件
//如果有黄色警告,是因为要Application遵循tabBar的协议,所以要强制转换一下告诉tabBar是遵循这个协议的
tabBarVC.delegate=(id)[UIApplication sharedApplication].delegate;
20.一个Xib可以描述很多个View
21. 登录注册两个View放在一个bigView上,点击切换注册按钮时,移动下面bigView的位置
22.
// viewDidLayoutSubviews:才会根据布局调整控件的尺寸
- (void)viewDidLayoutSubviews
{
// 一定要调用super 开发中一般在这个方法里设置布局,这个方法会被调用给你多次
[super viewDidLayoutSubviews];
}
23. //在封装UITextField,监听开始编辑事件
[self addTarget:self action:@selector(textBegin) forControlEvents:UIControlEventEditingDidBegin];
24 宏: #紧跟着后面的字符加一个双引号,定义宏时 @#aaa 就是@“aaa”
##是链接符号 比如abc##fileName 就是 abcfileName
25. [array addObjectsFromArray: arrayTwo]; //把arrayTwo数组里的元素,添加到array数组元素后面
26. @property(nonatomic,assign,getter=isFooterRefreshing)BOOLfooterRefreshing; //通常我们可以用getter来定义一个自己喜欢的名字
27. 下一页,页码发给服务器逻辑(上拉刷新) :
// parameters[@"page"] = @(self.page + 1);
[mgrGET:KrisCommonURL parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//存储maxtime
self.maxtime= responseObject[@"info"][@"maxtime"];
//字典数组->模型数据
NSArray *moreTopics = [BDJTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
//累加到旧数组的后面
[self.topics addObjectsFromArray:moreTopics];
// 刷新表格
[self.tableView reloadData];
// 结束刷新
[self footerEndRefreshing];
// self.page = [parameters[@"page"] integerValue];
}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试!"];
// 结束刷新
[self footerEndRefreshing];
// self.page--;
}];
28. //把oldArray数组的元素存储到 newArray 里从索引0开始存储,也就是存储到最前面
[self.newArray insertObjects:oldArray atIndexes:[NSIndexSet indexSetWithIndex:0]];
29. 服务器数据不怎么变的时候,可以传页码;很多公司不传页码,因为服务器经常有新数据的话,会蹩脚;
所以很多公司要求发最后一条数据的id给它来刷新数据,这样就不会出现数据断层
// 所以要判断一下,已有数据是否是最新数据,然后再下拉刷新判断:拿记录下的第一条数据的id进行请求
//发送请求给服务器,下拉刷新数据
- (void)loadNewTopics
{
// 1.取消之前的请求
// 取消所有的请求,并且关闭session(注意:一旦关闭了session,这个manager再也无法发送任何请求)
// [self.manager invalidateSessionCancelingTasks:YES];
[self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
// [self footerEndRefreshing];
// 2.拼接参数
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
parameters[@"a"] =@"list";
parameters[@"c"] =@"data";
parameters[@"type"] =@"31";
parameters[@"mintime"] = @"5345345";
// 3.发送请求
[self.manager GET:XMGCommonURL parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//存储maxtime
self.maxtime= responseObject[@"info"][@"maxtime"];
// //新数据直接覆盖之前数据
self.topics = [XMGTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
// if(self.topics){
// //把这个数组的元素从零存储到topics里
// [self.topics insertObjects:newTopics atIndexes:[NSIndexSet indexSetWithIndex:0]];
// }else{
// //新数据 直接覆盖之前数据
// self.topics=newTopics;
// }
// 刷新表格
[self.tableView reloadData];
// 结束刷新
[self headerEndRefreshing];
}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (error.code != NSURLErrorCancelled) { //并非是取消任务导致的error,其他网络问题导致的error
[SVProgressHUD showErrorWithStatus:@"网络繁忙,请稍后再试!"];
}
// 结束刷新
[self headerEndRefreshing];
}];
}
30.
// 取消之前所有的请求
// 取消所有的请求,并且关闭session(注意:一旦关闭了session,这个manager再也无法发送任何请求)
// [self.manager invalidateSessionCancelingTasks:YES];
[self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];
//执行了这个方法后,会来到failure的block
31. 几个cell相同的属性提取出来,创建一个父cell
XIb没有继承的特性,只能纯代码
32. 枚举
//typedef enum {
// /**全部*/
// XMGTopicTypeAll = 1,
// /**图片*/
// XMGTopicTypePicture = 10,
// /**段子*/
// XMGTopicTypeWord = 29,
// /**声音*/
// XMGTopicTypeVoice = 31,
// /**视频*/
// XMGTopicTypeVideo = 41
//} XMGTopicType;
typedefNS_ENUM(NSUInteger, XMGTopicType) {//使用枚举,参数可以说明枚举类型
/**全部*/
XMGTopicTypeAll = 1,
/**图片*/
XMGTopicTypePicture = 10,
/**段子*/
XMGTopicTypeWord = 29,
/**声音*/
XMGTopicTypeVoice = 31,
/**视频*/
XMGTopicTypeVideo = 41
};
32. Control + command +空格弹出表情文字标签键盘
Control + Command +⬆️/⬇️切换.m和.h
33. 控件的命名 —> 功能 + 控件类型
34. // 注册nibcell
UINib *nib = [UINib nibWithNibName:NSStringFromClass([XMGTopicCell class]) bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:XMGTopicCellId];
35. 图片上下左右边不拉伸,中间拉伸
找到图片选择 slices >> Horizontal and Vertical >>然后告诉图片上下左右哪些区域需要保护起来
或者 下面选择平铺/拉伸(最好要保证中间是纯色的)的范围
36. 调用方法时,左边有中文参数时,右边参数是没有提示的
37. 点击”前往” >> 按住option键 >> 会出来”资源库”等其他文件夹
38.
/*
插件的安装路径
1.旧版本路径:/Users/用户名/Library/Application Support/Developer/Shared/Xcode/Plug-ins
2.新版本路径:/Users/用户名/Library/Developer/Xcode/Plug-ins
*/
39. 想修改插件的话, 找到插件 >> Resource >> 更改Completion.plist文件
40. 图片浏览插件 KSImage
41. 公司需求要cell一种悬浮的效果:
- (void)setFrame:(CGRect)frame
{
frame.size.height-=10;
[supersetFrame:frame];
}
42. [UIFont systemFontOfSize:15].lineHeight; //一行文字的高度
43. xib里面Lable有个line Breaks选项,可以设置超出内容的部分怎么显示(省略号的位置),比如:让英文字母在label字母可以拆分显示下一行时可选择CharacterWrap
在纯代码开发中换行模式是: label.lineBreakMode = NSLineBreakByCharWrapping;
44.
1>每次刷新表格时,有多少数据,这个方法就一次性调用多少次(比如有100条数据,每次reloadData时,这个方法就会一次性调用100次)
2>每当有cell进入屏幕范围内,就会调用一次这个方法
//每次都调用这个方法为了计算contentSize
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath;
所以要缓存cell的高度
方法一: 用计算后的高度作为模型的一个属性
- (CGFloat)cellHeight
{
// 如果已经计算过,就直接返回
if (_cellHeight) return _cellHeight;
//文字的Y值
_cellHeight += 55;
//文字的高度
CGSizetextMaxSize =CGSizeMake(XMGScreenW- 2 *XMGMarin,MAXFLOAT);
_cellHeight += [self.text boundingRectWithSize:textMaxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:15]} context:nil].size.height + XMGMarin;
//工具条
_cellHeight += 35 + XMGMarin;
return _cellHeight;
}
方法二: 估算高度(如果展示滚动条不推荐此方法) 优点: heightForRow只是在用到的时候才调用进行cell高度计算,不会每次都调用
//设置cell的估算高度(每一行大约都是estimatedRowHeight)
self.tableView.estimatedRowHeight = 100;
缺点:滚动条长度不准确,不稳定,甚至卡顿效果,cellForRow和heightForRow的执行顺序也会发生变化,会先cellForRow
45.autoresizing 和 autolayout 是不能共存的.
一般情况下,以下这些view的autoresizingMask默认就是18(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)
1.从xib里面创建出来的默认控件
2.控制器的view
如果不希望控件拥有autoresizingMask的自动伸缩功能,应该设置为none
blueView.autoresizingMask = UIViewAutoresizingNone;
46. 懒加载: eg
- (XMGTopicVideoView *)videoView
{
if (!_videoView) {
XMGTopicVideoView *videoView = [XMGTopicVideoView xmg_viewFromXib];
[self.contentViewaddSubview:videoView];
_videoView= videoView;
}
return _videoView;
}
47.- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath ;这个方法执行之后才调用cell的- (void)layoutSubviews;
48.
/* iOS 9之前会报错
如果错误信息里面包含了:NaN,一般都是因为除0造成(比如x/0)
(NaN : Not a number)
*/
49. 有些人想 imageView里面添加 button 和label 和 label,但是不建议这么做,最后是用UIView和UIScrollView, Xib不接受这种做法因为这些控件里面本身就有控件,可能影响这些控件里的功能和排布,这些控件也是继承UIView控件的集合
50. xib 不设置宽高,让它朝一个方向对齐,控件会自动计算宽高
51. // %.3f 小数点有保留三位小数 // %04d : 占据4位,多余的空位用0填补
52. 在 appDelegata.m开始监控网络状态
// 开始监控网络状况
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
使用AFN获取网络状态:
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
mgr.isReachableViaWiFi/mgr.isReachableViaWWAN / else
53. // 获得缓存中原图(SDWebImage的图片缓存是用图片的url字符串作为key)
UIImage *originImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:topic.image1URL];
54.点语法要想提示必须有方法声明
55. @"foo" = @("foo")
56. 查看图片有三种情况: 长图 动图 原图. 把这些情况都加载都一个cell上,通过网路返回字段来判断显示哪些控件
57. // 控制Button内部的子控件对齐,不是用contentMode,是用以下2个属性
btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
btn.contentVerticalAlignment = UIControlContentVerticalAlignmentTop;
// 控件Button内部子控件之间的间距
btn.contentEdgeInsets = UIEdgeInsetsMake(10, 0, 0, 0);//button里面控件整体(文字+图片),上部空出10的内边距
btn.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);//button文字左边空出10的内边距(往右挪动10)
btn.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 10);// button图片右边空出10的内边距(往左边挪动10)
//注意: 两个控件分别左右挪动相同的距离,这样显示 两个控件依然居中
58. 按住option键 点击想要右侧展示的.m文件,会在Xib想拖线时快速定位到你想右侧想展示的.m文件
59. [string hasSuffix:@"gif”]; //string是否以gif结尾
[string hasPrefix:@"gif”]; //string是否以gif开头
[string.lowercaseString hasSuffix:@"gif”]; // string里的字符统一转换小写后是否以gif结尾
[string.uppercaseString hasSuffix:@"gif"]; // string里的字符统一转换大写后是否以gif开头
[string.pathExtension.lowercaseString isEqualToString:@"gif”]; //string拓展名转小写后是否等于 gif
60.对于图片的data来说,它的首字节是来描述图片类型的:比如SDWebImage用来图片下载完毕后判读图片类型的方法
+ (NSString*)sd_contentTypeForImageData:(NSData*)data {//这个方法使用于后台返回的图片加载链接是 //http:www.abc.com/test 这种没有后缀的情况
uint8_t c;
[datagetBytes:&clength:1];//获取图片首字节赋值给c
switch(c) {
case0xFF:
return@"image/jpeg";
case0x89:
return@"image/png";
case0x47:
return@"image/gif";
case0x49:
case0x4D:
return@"image/tiff";
case0x52:
// R as RIFF for WEBP
if([datalength] < 12) {
returnnil;
}
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
if([testStringhasPrefix:@"RIFF"] && [testStringhasSuffix:@"WEBP"]) {
return@"image/webp";
}
returnnil;
}
return nil;
}
61. self.imageView.contentMode = UIViewContentModeTop;//图片触顶,图片是不会拉伸图片的
self.imageView.clipsToBounds = YES; //多余部分减掉
62.
//清除内存缓存
[[SDImageCache sharedImageCache] clearMemory];
// 设置缓存时长为1个月
[SDImageCache sharedImageCache].maxCacheAge = 30 * 24 * 60 * 60;
// 清除沙盒中所有使用SD缓存的过期图片(缓存时长 > 一个星期)
[[SDImageCache sharedImageCache] cleanDisk];
// 清除沙盒中所有使用SD缓存的图片
[[SDImageCache sharedImageCache] clearDisk];
63. SDWebImage其实缓存存储设置是以 字典的形式存储的,key绑定image,key对image强引用,清除内存缓存的原理是清除key,自然内存中的image也会被销毁
cell图片 离开屏幕没有被强引用的话就会被销毁,后面再进来的时候回先从内存中加载看是否存在图片,不存在的话在沙盒中查找图片
64. FPS就是一秒钟渲染多少帧 Frame Per Second = FPS,值最佳为60左右,这个值是小于60代表卡顿. demo检测好的三方有YYFPSLabel
65. 保存图片到相册: 1> 保存图片到[相机胶卷] 2> 创建一个属于自己的相册 3>将刚才保存到[相机胶卷中的图片引用到[自定义相册]
66.
使用weak和assign修饰OC对象的区别
1>成员变量
1) weak生成的成员变量是用__weak修饰的,比如XMGCat * __weak _cat;
2) assign生成的成员变量是用__unsafe_unretained修饰的XMGCat * __unsafe_unretained _cat;
2> __weak和__unsafe_unretained
1)都不是强指针(不是强引用),不能保住对象的命
2) __weak :所指向的对象销毁后,会自动变成nil指针(空指针),不再指向已经销毁的对象
3) __unsafe_unretained :所指向的对象销毁后,仍旧指向已经销毁的对象
67. 模态弹出: 用现在所在的window最好拿的就是根控制器
[self.window.rootViewController presentViewController:vc animated:YEScompletion:nil];
或者
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:vc animated:YES completion:nil]; (推荐)
68.[self.viewinsertSubview:scrollViewatIndex:0]; //放在所有子控制器view的最前面
69. 一种常见的布局适配中开发步骤:
sp1.在viewDidLoad方法中添加初始化子控件
sp2.在viewDidLayoutSubviews方法中布局子控件(设置子控件的位置和尺寸)
另一种常见的开发思路:
sp1. 控件弄成懒加载
sp2. 在viewDidLayoutSubviews方法中布局子控件(设置子控件的位置和尺寸)
70. // 图片缩小放大
self.imageView= imageView;
CGFloatmaxScale =width/ imageView.kris_width;
if(maxScale > 1) {
scrollView.maximumZoomScale= maxScale;// 设置最大放大比例
scrollView.delegate=self;
}
#pragma mark -
- (UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView
{
return self.imageView;
}
71.
[[NSBundlemainBundle]pathForResource:@"Info"ofType:@"plist"]; //普通.plist文件内的信息用这个方法就可以获取到内容
[NSBundlemainBundle].infoDictionary[@"CFBundleName"]; //获取系统的.plist文件内容用这种方法
72. 设置模拟器运行显示语言: sp1 在模拟器设置语言为简体中文 sp2 点击蓝色文件夹>>右侧点击蓝色文件夹 >> 在”Localizations” 点击 “+” >> 加上简体中文再运行就可以了
73. UI_USER_INTERFACE_IDIOM() = UIUserInterfaceIdiomPad;//当前设备运行的是平板
74. 父类不应该依赖于子类,抽成属性/get方法,供子类赋值.get方法供子类重写更好些
子类利用变量get方法重写返回了一个值给父类
75. 封装: 1.组合类 2.继承(依赖性很强)
76. [self.tableView.mj_footer endRefreshingWithNoMoreData]; //结束刷新,不再加载新数据,并提醒加载完毕
77. 框架建议使用者子类化第三方框架