一 、使用git管理工程
1、可以使用OSChina远程管理工程(免费) 2、可以使用GitHub网站进行远程管理(付费) 注册--登录--创建资源库
二、通过coco管理我们的第三方框架
1、通过命令加载到我们的工程统计的文件夹 2.命令行pod init 创建pod file 文件 3、命令行pod search +第三方框架的名字 ,进行搜索 4、搜索到第三方框架,把最新的版本复制到我们的podfile文档 5、选择我们键盘上的Q退出 6、命令行安装我们的第三方框架pod install
三、在本地checkout
1、使用Xcode进行checkout,把资源加载到本地 2、用xocde创建工程,把工程放方到和git同级的文件,让git管理工程 3、创建完工程,commit--push到我们的OSChana远程服务管理器
四、开始我们的环境配置
1、打开生成的新生成的工程对应的工程 2、配置我们的环境 3、工程的唯一标示,(一般的时候都是我们的公司名称网址的反写,例如com.520it.www.+我们工程的名字) 4、工程的版本,如果是新开发的工程,一般是1.0,如果是迭代开发,每次发布的版本必须比我们的上一次发布的版本要高 5、配置我们工程的文件的前缀(在右边--例如LYH) 6、配置我们是配手机的版本,一般最多比我们最新版本低三级 7、配置我们手机的横竖屏 8、配置我们启动App的status bar style 9、配置我们App的图标AppIcon 10、配置我们启动App的Launch image Source 选择BrandAssets 11、选择我们是否选择加载Storyboard
五、正式开始我们的工程--控制器的选择(以百思不得姐为例)
1、首先显示我们的窗口 2、选择tabBarController为我们的根控制器 3、选择navegationController为我们根控制器的第一个根控制器 4、选择tableViewController为我们的nav的根控制器
六、工程的部署
1、划分工程的结构
2、删除工程的文件智能在Xcode中删除
3.git不会把空文件夹上传到远方的服务器
4、封装:可以做到自己的事情自己做
5、tabBarController切换原理:点击tabBar上的按钮,就会把子控制器的View添加到tabBarController,把之前的View移除掉
6、在自定义的tabBarController中搭建我们的主流框架
7、添加对应的控制器到对应的位置
8、添加完毕子控制器
9.tabBar按钮出现的问题解决
(1)、按钮选中的时候,图片被渲染
原因:苹果默认设置渲染颜色,为蓝色
解决:1.直接修改图片 :设定我们的图片为original2.通过代码 创建分类设定图片不被渲染
(2)、按钮被选中的时候,文字被渲染,设置字体大小
原因:苹果默认设置渲染颜色,为蓝色
解决:文字在tabBar按钮上,文字的属性有tabBarItem决定,(建议在tabBarController中进行统一设置 1、通过在方法l-(void)load中进行设置文字属性,此方法在程序启动的时候加载 2、在+ (void)initialize 中进行设置,此方法在类第一次使用或者子类第一次使用的时候加载)
(3)、中间发布按钮显示不出来
10、关于获取所有的控件的方法说明appearence
1.appearance是什么?UIAppearance协议里面一个方法
2.任何对象都可以使用appearance?不能,只有遵守了UIAppearance协议,才能使用UIAppearance,所有的控件都可以使用appearance
3.任何属性都可以通过appearance去设置吗?不是任何属性都可以通过appearance设置
4.哪些属性可以通过appearance去设置,只有有UI_APPEARANCE_SELECTOR宏属性才可以通过appearance去设置
5.如果一个属性通过appearance去设置,必须要保证在显示之前去设置
//获取所有UITabBarItem外观
UITabBarItem*item = [UITabBarItemappearance];
//文字颜色为黑色
//字典描述文字信息
NSMutableDictionary*attr = [NSMutableDictionarydictionary];
attr[NSForegroundColorAttributeName] = [UIColorblackColor];
//设置选中状态下文字颜色
[itemsetTitleTextAttributes:attrforState:UIControlStateSelected];
11、关于文字渲染的问题
设置文字不要渲染
//技巧:以后不要给我记方法,忘记,直接跳入头文件去查找
//通过富文本属性去设置文字颜色,字体,阴影,下划线,图文混排等等
// tabBarItem:模型通过富文本属性设置字符串
// tabBarItem不是按钮,只是按钮对应模型
12、设置文字的大小
设置tabBar上文字的大小只有设置文字在正常状态下的文字大小,在选中状态下无法设置文字的大小
NSMutableDictionary*attr = [NSMutableDictionarydictionary];
attr[NSForegroundColorAttributeName] = [UIColorblackColor];
//设置选中状态下文字颜色
[itemsetTitleTextAttributes:attrforState:UIControlStateSelected];
//设置正常状态下文字字体
NSMutableDictionary*attrNor = [NSMutableDictionarydictionary];
attrNor[NSFontAttributeName] = [UIFontsystemFontOfSize:13];
[itemsetTitleTextAttributes:attrNorforState:UIControlStateNormal];
13、关于中间图片不显示问题
主要原因是中间按钮被渲染
14、关于中间图片位置错乱问题
重新把一个按钮添加到tabBar上,建议在Viewdidload中加载,设置懒加载
15、关于导航条按钮点击范围较大问题
默认一个按钮,超出按钮点击范围,将无法点击,如果能够点击影响用户体验
为什么把一个按钮包装成UIBarButtonItem就会出现点击范围较大
解决:不能把一个按钮包装成UIBarButtonItem;
创建分类,提供接口,把我们需要的Item作为方法返回
+ (instancetype)itemWithImage:(UIImage*)image highImage:(UIImage*)highImage target:(id)target action:(SEL)action
{
UIButton*btn = [UIButtonbuttonWithType:UIButtonTypeCustom];
[btnsetImage:imageforState:UIControlStateNormal];
[btnsetImage:highImageforState:UIControlStateHighlighted];
[btnsizeToFit];
[btnaddTarget:targetaction:actionforControlEvents:UIControlEventTouchUpInside];
UIView*containerView = [[UIViewalloc]initWithFrame:btn.bounds];
[containerViewaddSubview:btn];
return[[UIBarButtonItemalloc]initWithCustomView:containerView];
}
16、关于导航条上中间文字的属性设置
显示哪个子控制器,对应的子控制器就可以设置对应的文字标题属性,文字属性是有navgetionbar决定的。
17、关于导航条处理细节
要想设置全局的导航条主标题文字设置:
建议在主流框架的navgetion获取当前类的全局导航条,设置导航条的字体为想要设定的字号。
eg://设置导航条标题字体=>导航条
NSMutableDictionary*attr = [NSMutableDictionarydictionary];
attr[NSFontAttributeName] = [UIFontboldSystemFontOfSize:22];
//获取全局导航条外观
// [UINavigationBar appearance];
// iOS7,发短信功能,联系人黑屏=>使用appearance,去设置导航条背景图片
//获取哪个类下的导航条,管理自己下导航条
UINavigationBar*bar = [UINavigationBarappearanceWhenContainedIn:self,nil];
[barsetTitleTextAttributes:attr];
18、关于返回按钮的设置;
- (void)pushViewController:(UIViewController*)viewController animated:(BOOL)animated,关于push的调用是每次push的时候,都会调用,把push的控制器压入栈顶控制器中,
设置除根控制器的每次push的控制器左边按钮为想要的返回按钮的样式;(注意:⚠️每次设置左边的按钮的时候必须在跳转之前设置);
eg:- (void)pushViewController:(UIViewController*)viewController animated:(BOOL)animated
{
//设置栈顶控制器
//设置返回按钮
UIButton*backButton = [UIButtonbuttonWithType:UIButtonTypeCustom];
[backButtonsetTitle:@"返回"forState:UIControlStateNormal];
[backButtonsetTitleColor:[UIColorblackColor]forState:UIControlStateNormal];
[backButtonsetTitleColor:[UIColorredColor]forState:UIControlStateHighlighted];
[backButtonsetImage:[UIImageimageNamed:@"navigationButtonReturn"]forState:UIControlStateNormal];
[backButtonsetImage:[UIImageimageNamed:@"navigationButtonReturnClick"]forState:UIControlStateHighlighted];
[backButtonsizeToFit];
//设置内容内边距,修改按钮位置
backButton.contentEdgeInsets=UIEdgeInsetsMake(0, -30,0,0);
[backButtonaddTarget:selfaction:@selector(back)forControlEvents:UIControlEventTouchUpInside];
UIView*containView = [[UIViewalloc]initWithFrame:backButton.bounds];
[containViewaddSubview:backButton];
UIBarButtonItem*item = [[UIBarButtonItemalloc]initWithCustomView:containView];
viewController.navigationItem.leftBarButtonItem= item;
//真正在执行跳转
[superpushViewController:viewControlleranimated:animated];
}
19 关于滑动返回的设置
⚠️导航控制器跟我们设置了push之后自动返回功能,这个功能是ios7开始的,如果我们自己设置了导航条左侧返回按钮,覆盖了系统的返回按钮,那么左侧边缘的滑动返回功能就会失效,这个时候我们需要通过代码来实现左侧滑动返回功能
苹果设置左侧返回失效,可能系统内部对手势功能做了一些设置
这个时候我们需要看苹果做了哪些事情,我们把苹果做的事情取消就可以了,
- (void)viewDidLoad {
[superviewDidLoad];
//清空滑动返回手势代理,恢复滑动返回功能
self.interactivePopGestureRecognizer.delegate=self;
//假死状态:界面死,程序还在跑
//原因:在根控制器下,滑动返回
//解决:控制滑动手势什么时候有效,什么时候失效
//干掉手势,没有滑动返回功能,
//手势失效,通过代理
// self.interactivePopGestureRecognizer.delegate = self;
}
#pragma mark -UIGestureRecognizerDelegate
//是否触发手势
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch
{
//在根控制器下失效,在非根控制器有效
returnself.childViewControllers.count>1;
}
通过查找我们知道苹果内部把手势的代理手势用户交互为NO(是否触发手势),所以只要我们重新设置代理,然后把用户交互触发手势设置在非根控制器为YES就可以了
20、关于设置全屏的左滑功能
这个时候我们需要先禁用系统自带的左侧边缘滑动,然后重新进行设置代理,调用系统的手势方法,然后设置手势滑动在非根控制器下为YES;
21、设置程序启动的时候AD广告界面
设置广告界面为在程序启动完毕的时候为我们的根控制器,(其中还必须能够显示启动图片)
通过XIB来创建我们的广告界面,其中广告图片来自网络,所以我们不能加载本地图片,要加载网络图片这个时候我们就用到了占位思想,这里就是设置占位图片。
22、设置我们的启动图片的屏幕适配问题
- (void)setupLanuchImage
{
//不同屏幕尺寸使用不同图片
//屏幕适配
//判断屏幕尺寸
// iPhone6P:736 iPhone6:667 iPhone5:568 iPhone4:480
UIImage*image =nil;
if(iPhone6P) {// iPhone6P
image = [UIImageimageNamed:@"LaunchImage-800-Portrait-736h@3x"];
}elseif(iPhone6) {
image = [UIImageimageNamed:@"LaunchImage-800-667h"];
}elseif(iPhone5) {
image = [UIImageimageNamed:@"LaunchImage-568h"];
}elseif(iPhone4) {
image = [UIImageimageNamed:@"LaunchImage"];
}
_lanuchImageView.image= image;
}
23加载网络图片这个时候我们需要加载第三方框架
第三方框架的管理,使用cocoapods,使用它的好处是可以自动加载我们需要的第三方框架的依赖,不需要我们手动再去加载,因为我们在开发的时候并且会自动更新我们的第三方框架。
24、通过第三方框架加载AFN加载数据
1)创建我们的会话管理者,让会话管理者发送请求
2)如果遇到请求失败,看返回给我们请求失败的原因,
eg:content-type;
25、广告的跳转
给广告的imageView设置一个点按手势(⚠️imageView默认时不能与用户交互的,必须让图片的能够与用户交互,设置enabled = YES);
26、广告的时间设定
通过实践定时器,设置广告的时长,通过static设定只给变化的时间参数分配一次空间,
//添加倒计时功能
_timer= [NSTimerscheduledTimerWithTimeInterval:1target:selfselector:@selector(timeChange)userInfo:nilrepeats:YES];
}
- (void)timeChange
{
staticinti =3;
i--;
if(i == -1) {
//计时结束
[selfjump:nil];
}
//设置按钮标题
NSString*title = [NSStringstringWithFormat:@"跳过(%d)",i];
[_jumpButtonsetTitle:titleforState:UIControlStateNormal];
}
27 、 标签界面的设定
创建标签控制器
28、自定义cell
建议通过XIB+代码的形式创建自定义cell,给cell上的空间设置数据
29、加载数据
通过查询数据的接口文档查询要加载的数据,发送网络请求
30、订阅数字的修改
通过NSString设定想要加载的数据
31、头像圆角的设置
两种方式:
(1)、通过layer的剪切
(2)、通过图像的上下文剪切
if(image ==nil)return;
// 1.开启图形上下文
// opaque:不透明度YES:黑色NO:透明
// scale:比例因子(像素与点比例) 0:自动识别当前比例因子
UIGraphicsBeginImageContextWithOptions(image.size,NO,0);
// 2.描述裁剪区域
UIBezierPath*clipPath = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0, image.size.width, image.size.height)];
// 3.设置裁剪区域
[clipPathaddClip];
// 4.画图
[imagedrawAtPoint:CGPointZero];
// 5.从上下文取出图片
image =UIGraphicsGetImageFromCurrentImageContext();
// 6.关闭上下文
UIGraphicsEndImageContext();
// 7.一定要给控件重新赋值
_iconView.image= image;
32、tableView的分割线为样式
(1)、自定义分割线
通过去处系统的分割线,加上自己制定一的分割线
(2)设置系统属性,让分割线占据全屏
//版本适配iOS7
iOS多了一个属性separatorInset
self.tableView.separatorInset=UIEdgeInsetsZero;
版本IOS8
多了一个约束边缘属性
layerMargins
if(version >=8.0) {//判断当前版本
cell.layoutMargins=UIEdgeInsetsZero;
}
******想要重新设定cell的尺寸,那么cell又一个setframe
可以在这里面设定cell的尺寸
- (void)setFrame:(CGRect)frame
{
// frame.origin.y += 1;
// frame.origin.x += 10;
frame.size.height-=1;
// frame.size.width -= 20;
//真正去设置frame
[supersetFrame:frame];
}
33、指示器效果
主要要与用户加载网络数据的时候提醒用户的功能,还必须了解,view消失的时候需要做的事情,
34、关于文字换行
35、当一个界面比较复杂时,把界面分成几个模块,还有我们要考虑使用封装的思想,便于应对界面的变化
36、文本框的占位颜色
这个属性属于视图,所以可以通过tintcolor来设置
eg:self.tintColor= [UIColorwhiteColor];
37、关于文本框的占位文字颜色
因为文本框没有给我们提供文本框的占位文字颜色设置,所以我们
只能设置占位文字的属性来设置占位文字的颜色,
eg://初始化文本框占位文字颜色
NSMutableDictionary*attr = [NSMutableDictionarydictionary];
attr[NSForegroundColorAttributeName] = [UIColorlightGrayColor];
NSAttributedString*attrStr = [[NSAttributedStringalloc]initWithString:self.placeholderattributes:attr];
self.attributedPlaceholder= attrStr;
38、快捷设置文本框占位文字颜色
可以通过设置分类来给占位文字增加颜色属性
@proprety UIColor * placeholder;
-(void)setPlaceholder:(UIColor *)color {
NSMutableDictionary*attr = [NSMutableDictionarydictionary];
attr[NSForegroundColorAttributeName] = placeholderColor;
NSAttributedString*attrStr = [[NSAttributedStringalloc]initWithString:self.placeholderattributes:attr];
self.attributedPlaceholder= attrStr;
}
39、考虑占位文字是什么空间,可能是UILable,所以如果能拿到UILable
我们只要设置UILalbe的就可以设置占位文字的颜色textColor
如果类没有给我们提供空间,我们可以通过断点和小面包查看是什么空间,然后通过KVC
取出空间,给空间设置属性,
//猜测占位文字是UILabel =>验证占位文字是UILabel(通过小面包查看当前界面是哪个类) =>设置占位文字颜色=>拿到这个占位文字label做事情=>苹果木有提供这样属性给我拿这个控件=>思考:有些属性可能存在,但是是私有没有暴露给我们=>查看下这个类私有属性名(1.runtime 2.断点) => KVC
//直接获取控件去设置
UILabel*placeholderLabel = [selfvalueForKey:@"placeholderLabel"];
placeholderLabel.textColor= placeholderColor;
40、怎样设置让空间的设置属性没有先后顺序
OC的机制是懒加载,用到的时候在加载,所以要想设置没有先后顺序可以判断空间
有没有占位文字,如果没有。我们在设置字符长度为空
// OC是懒加载,用到的时候才会去加载
//直接获取控件去设置
//注意点:判断字符串有没有内容根据长度判断
if(self.placeholder.length==0) {
self.placeholder=@" ";
}
//获取控件
UILabel*placeholderLabel = [selfvalueForKey:@"placeholderLabel"];
//设置颜色
placeholderLabel.textColor= placeholderColor;
41、对于固定不变的页面我们一般可以通过storyboard来创建
42、设置我的界面的collectionView的分割线
我们可以通过设置间隙来设置collectionView的分割线
43、为了方便我们看代码,我们一般都会通过抽取,来是代码跟一目了然
之前我们一直都是通过把自己的功能放倒自己的功能模块,现在我们可以通过
UICollectionView*collectionView = ({
collectionView = [[UICollectionViewalloc]initWithFrame:CGRectMake(0,0,0,300)collectionViewLayout:layout];
collectionView.backgroundColor= [UIColorclearColor];
//设置数据源.展示cell
collectionView.dataSource=self;
//注册cell
[collectionViewregisterNib:[UINibnibWithNibName:@"XMGSquareCell"bundle:nil]forCellWithReuseIdentifier:ID];
collectionView;
});
44、关于网络数据的加载和模型转换
获取网络数据-查看接口文档--创建会话管理者--设置请求参数--发送请求--接受数据--先写入plist文件,设置模型参数,字典数组转模型,传递数据,设置到对应的cell上。
45、关于collection的行高
求出collection的实际行高,计算出footerView的实际行高我们在重新把值赋值给footerView。
46、关于collectionView空格子的处理
格子的多少有模型决定所以我们要修补空格子,就必须修改模型
47、点击cell进入网页
展示网页:
1.UIWebView好处:在当前app打开网页,弊端:没有功能,自己去实现,(进度条)
2.Safari:好处:默认有很多好用功能(进度条,地址栏,前进,后退,刷新)弊端:必须要跳出当前app
3.在当前app展示网页,而且想要有safari功能,自定义UIWebView
4.SFSafariViewController:Safari iOS9展示网页,当前app展示网页,有safari所有功能
ios8 有一个Webkit显示网页;
通过KVO监听来改变,网页的进退;
48、清楚内存的设置
通过获取出的尺寸和位置来达到计算内存的大小和位置
49、获取文件夹的尺寸
1、获取NSFileManager对象
2、获取文件夹里面的所有文件
3、遍历文件夹的所有文件
4、拼接文件全路径
5、attributesItemAtPath:指定一个文件全路径
6、获取文件尺寸,叠加起来
//获取文件夹尺寸
- (NSInteger)getSizeOfDirectoryPath:(NSString*)directoryPath
{
// 1.获取NSFileManager对象
NSFileManager*mgr = [NSFileManagerdefaultManager];
// 2.获取文件夹里面所有文件
// subpathsAtPath:获取文件夹里面所有子路径,包含多级.
NSArray*subpaths = [mgrsubpathsAtPath:directoryPath];
NSIntegertotalSize =0;
// 3.遍历文件夹里所有文件
for(NSString*fileNameinsubpaths) {
// 4.拼接文件全路径
NSString*filePath = [directoryPathstringByAppendingPathComponent:fileName];
//判断下是否是隐藏文件或者是文件夹
if([fileNamehasPrefix:@"."])continue;//隐藏文件
//判断下是否是文件夹
BOOLisDirectory;
[mgrfileExistsAtPath:filePathisDirectory:&isDirectory];
if(isDirectory)continue;//文件夹
// 5.获取文件属性
NSDictionary*attr = [mgrattributesOfItemAtPath:filePatherror:nil];
// 6.叠加文件尺寸
totalSize += [attrfileSize];
}
returntotalSize;
}
50、在cell上显示数据
拼接字符和数据就可以
51、清楚缓存
思路:1、点击cell的时候删除全路径下所有文件
2、创建路径下文件夹‘
3、修改数据为0
4、刷新列表。
- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
//清除缓存
// 1.删除文件夹
[[NSFileManagerdefaultManager]removeItemAtPath:XMGCachePatherror:nil];
// 2.创建文件夹
[[NSFileManagerdefaultManager]createDirectoryAtPath:XMGCachePathwithIntermediateDirectories:YESattributes:nilerror:nil];
//刷新表格
_totalSize=0;
[self.tableViewreloadData];
// [[SDImageCache sharedImageCache] clearDisk];
}
52、封装业务类
封装的要求
1、业务类顶部,写清楚这个类是干什么的
2、每个方法都必须有文档主食,外界调用的时候有提示
3、每个功能,一定要严谨判断。
eg:我们的文件缓存处理
/**
*功能:处理文件夹
*/
@interfaceXMGFileManager :NSObject
/**
*指定一个文件夹路径,获取这个文件夹尺寸
*
* @param directoryPath文件夹全路径
*
* @return文件夹尺寸
*/
+ (NSInteger)getSizeOfDirectoryPath:(NSString*)directoryPath;
/**
*删除文件
*
* @param filePath删除文件全路径
*/
+ (void)deleteOfFilePath:(NSString*)filePath;
53、关于处理缓存的时候App卡顿的现象解决
因为所有文件的拼接和查询文件都是在主线程中执行,所以会造成主线程的卡顿,所以我们要把耗时的操作都放在,
之线程中操作,所以这个时候我们可以痛哟Block传递参数,把操作放在子线程中,就不会造成主线程卡顿
dispatch_async(dispatch_get_global_queue(0,0), ^{
// 2.获取文件夹里面所有文件
// subpathsAtPath:获取文件夹里面所有子路径,包含多级.
NSArray*subpaths = [mgrsubpathsAtPath:directoryPath];
NSIntegertotalSize =0;
// 3.遍历文件夹里所有文件
for(NSString*fileNameinsubpaths) {
// 4.拼接文件全路径
NSString*filePath = [directoryPathstringByAppendingPathComponent:fileName];
//判断下是否是隐藏文件或者是文件夹
if([fileNamehasPrefix:@"."])continue;//隐藏文件
//判断下是否是文件夹
BOOLisDirectory;
[mgrfileExistsAtPath:filePathisDirectory:&isDirectory];
if(isDirectory)continue;//文件夹
// 5.获取文件属性
NSDictionary*attr = [mgrattributesOfItemAtPath:filePatherror:nil];
// 6.叠加文件尺寸
totalSize += [attrfileSize];
}
dispatch_sync(dispatch_get_main_queue(), ^{
/**
*一定要记得回到主线程
*/
if(completion) {
completion(totalSize);
}
});
});
54、精华界面的搭建
关于精华界面的搭建,如果我们使用UIScrollerView就会造成离屏渲染,渲染也会创建很多对象,比较消耗内存
所以我们可以使用,UICollectionView来代替UIScrollerView,collectionView帮我们
实现了离屏渲染的问题。因为cell的重用机制
那么如何处理数据的错乱呢,我们可以在马上要显示的Cell上一处之前的view,再把我们哟啊吸显示的view添加到我们的cell上
55、如何显示topView顶部条的标题
我们可以仿照tabBar的设计。来设置顶部条,因为每个控制器都有,一个titel属性,所以,我们可以把控制器的title属性赋值,然后创建顶部条的标题时,把控制器的条内容赋值给Btn
56、监听顶部按钮的点击
但点击按钮的时候让对应的按钮处于选中状态(重要的三部曲)
57、监听滚动完成然tableView处于对应的状态
1、点击按钮的时候把要显示的view添加到cell上
2、滚动cell的时候让按钮 滚动到对应的位置
58、添加按钮底部条的下划线
可以在添加按钮的时候,把底部条,默认放在第一个按钮的下边,但点击
按钮的时候把底部条改变X的的位置,处于对应按钮的下边,当滚动cell的时候让其处于对应的按钮下边
59、对于一个App里面我们可以重复利用的界面,可以进行封装,方便我们重复利用
封装的要求是:把不改变的进行封装,改变的另外写一个类。
60、对于不等高的cell的搭建
对于比较复杂的cell我们需要静心模块封装,防止以后对要变动的改变
eg:我们的精华cell可以分为,顶部View,中间View,热评的View,底部View
61、顶部View的搭建
顶部View建议通过XIB+代码的方式进行搭建,
62、请求数据
通过AFN第三方框架我们进行请求数据,
查看接口文档-查看请求参数-发送请求-进行文档解析 -数据转模型
63、解析数据的过程
先要查看数据结构--看是否需要序列化--不需要序列化截取我们需要的shuju
--字典转模型--刷新列表
64、分析控件的frame
想要计算空间的frame,必须在我们请求数据成功之后进行frame计算
⚠️:尽量不要在heightforRow计算我们的行高,因为调用过于频繁,会造成界面卡顿
计算cell的高度,可以通过获取字体的字号和文字的宽度进行计算
65、MVVM框架
VM :视图模型 专门处理界面的业务逻辑,(计算空间的位置,点击事件)
思路:进行数据转模型完之后,这个时候我们需要计算出空间的行高,如果在控制器中计算显得控制器代码过于臃肿,这个时候我们可以使用MVVM框架来对控制器进行减负处理,把控制器管理
控件的frame和点击等事件静心VM处理。
VM的处理,就是把数据模型传递给视图模型,视图模型把计算好的frame储存到视图模型,然后给视图传递视图模型,展示数据。
66、搭建中间图片的View
中间图片的View搭建,其实和顶部视图搭建方法相似,参考顶部view的搭建过程
67、关于中间图片frame高度的计算
首先判断是不是文本cell,如果不是,就计算cell的frame
关于frameH的计算,让图片的高度和宽度进行等比列计算,
68、关于cell的循环利用
当是文本的时候我们需要隐藏cell的中间view,不是文本的时候让hidden的属性为NO
69、对于大图的处理
我们可以设置当图片尺寸大于屏幕的高度的高度的时候设置图片的高度,这个时候还需要设置图片的压缩性,
70、关于大图的处理
对于大图不能占据屏幕宽度,我们可是使用绘制图片获得一张新图,来重新布置图片
71、加载图片的进度处理
我们一般使用第三方框架来处理,对于精华加载图片的样式可以使用DALabeledCircularProgressView来调用其中的方法来实现,加载图片的进度
72、加载音频
加载音频的过程和之前加载图片的过程基本相似
创建音频的View--通过XIB进行设计音频的图形设计--查看接口文档定义属性
--传递视图模型--设置图形的frame,给音频View传递数据,连线设置数据
73、搭建视频View
和加载音频过程类似:
创建视频的View--通过XIB进行设计视频的图形设计--查看接口文档定义属性
--传递视图模型--设置图形的frame,给视频View传递数据,连线设置数据
74、搭建最热评论
过程和加载视频过程类似
创建最热评论的View--通过XIB进行设计最热评论的图形设计--查看接口文档定义属性
--传递视图模型--设置图形的frame,给最热评论View传递数据,连线设置数据
⚠️加载最热评论的数据属性:
其中涉及到加载过程属性嵌套的问题,这个时候我们需要对数据进行分析,MJE不会帮我们转换NSArray的属性,这个时候我们需要告诉它,我们要加载的数组属性是哪个类或者再次使用MJ转换模型
- (void)setTop_cmt:(NSArray*)top_cmt
{
_top_cmt= top_cmt;
if(top_cmt.count) {
NSDictionary*commentDict = top_cmt.firstObject;
_hotCommentItem= [XMGCommentItemmj_objectWithKeyValues:commentDict];
}
}
/*****************************************/
//告诉MJ,数组中字典转换成哪个模型
+ (NSDictionary*)mj_objectClassInArray
{
return@{@"top_cmt":@"XMGCommentItem"};
}
//在赋值之前,MJ就已经把这个数组中字典转换好模型,把模型包装到数组,传递给你
- (void)setTop_cmt:(NSArray*)top_cmt
{
_top_cmt= top_cmt;
if(top_cmt.count) {
_hotCommentItem= top_cmt.firstObject;
}
}
⚠️:如果模型中有模型会自动帮我们转换为模型
如果模型中有数组,就不会帮我们转换为模型
//如果模型中有模型,会自动帮你转换好
//如果模型中有数组,数组中是字典,就不会把数组中字典转换成模型
@interfaceXMGCommentItem :NSObject
@property(nonatomic,strong)NSString*content;
@property(nonatomic,strong)NSString*voicetime;
@property(nonatomic,strong)NSString*voiceuri;
@property(nonatomic,strong)XMGUserItem*user;
75、底部工具条的搭建
创建底部工具条的View--通过XIB进行设计底部工具条的图形设计--查看接口文档定义属性
--传递视图模型--设置图形的frame,给底部工具条View传递数据,连线设置数据
⚠️:底部接受的数据进行处理。
if(count >10000.0) {
CGFloatvalue = count /10000.0;
title = [NSStringstringWithFormat:@"%.1f万",value];
title = [titlestringByReplacingOccurrencesOfString:@".0"withString:@""];
}elseif(count >0){
title = [NSStringstringWithFormat:@"%ld",count];
}
[buttonsetTitle:titleforState:UIControlStateNormal];
76、关于cell外观的设计
主要是cell的方法set frame的应用。
77、cell顶部点击更多的处理。
主要是当点击更多数据的传递,(代理,block,通知的应用)
//通知:让两个没有关系对象,产生联系,用于多级传递
//代理:1.逆传2.封装自己控件
// block:1.用于参数2.逆传(替换代理)
2)想要拿到控制器做事情,就想到根控制器
// Modal =>只要有控制器
//以后想要快速获取控制器,就拿窗口的根控制器
[[UIApplicationsharedApplication].keyWindow.rootViewControllerpresentViewController:alertVcanimated:YEScompletion:nil];
78、关于时间的处理
NSDateFormatter时间格式的处理
关于NSCalendar日期元素的获取
// 利用NSCalendar处理日期
NSCalendar*calendar = [NSCalendarcurrentCalendar];
NSIntegermonth = [calendar component:NSCalendarUnitMonthfromDate:date];
NSIntegerhour = [calendar component:NSCalendarUnitHourfromDate:date];
NSIntegerminute = [calendar component:NSCalendarUnitMinutefromDate:date];
获取时间的间隔:
// 获得createdAtDate和nowDate的时间间隔(间隔多少秒)
// NSTimeInterval interval = [nowDate timeIntervalSinceDate:createdAtDate];
NSTimeIntervalinterval = [createdAtDate timeIntervalSinceNow];
// 获得日期之间的间隔
NSCalendarUnitunit =NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond;
NSDateComponents*cmps = [calendar components:unit fromDate:createdAtDate toDate:otherDate options:0];
NSLog(@"%@", cmps);
增加的日期分类
- (NSDateComponents*)deltaWithNow
{
//获取当前时间
NSDate*currentDate = [NSDatedate];
//获取日历
NSCalendar*calendar = [NSCalendarcurrentCalendar];
//获取两个日期差值
return[calendarcomponents:NSCalendarUnitHour|NSCalendarUnitMinutefromDate:selftoDate:currentDateoptions:NSCalendarWrapComponents];
}
- (BOOL)isThisYear
{
//获取当前时间
NSDate*currentDate = [NSDatedate];
//获取当前时间年份日期组件对象
NSCalendar*calendar = [NSCalendarcurrentCalendar];
//指定一个日期,就返回这个日期的日期组件
//获取当前时间日期组件
NSDateComponents*curCmp = [calendarcomponents:NSCalendarUnitYearfromDate:currentDate];
//获取发布时间日期组件
NSDateComponents*postCmp = [calendarcomponents:NSCalendarUnitYearfromDate:self];
//判断下年份是否与当前时间相等
returncurCmp.year== postCmp.year;
}
- (BOOL)isToday
{
//获取当前日历类
NSCalendar*curCalendar =[NSCalendarcurrentCalendar];
return[curCalendarisDateInToday:self];
}
- (BOOL)isYesterday
{
//获取当前日历类
NSCalendar*curCalendar =[NSCalendarcurrentCalendar];
return[curCalendarisDateInYesterday:self];
}
79、大图的展示
创建控制器展示想要展示的图片
80、关于图片的缩放
因为scrollerView自带缩放功能,所以只要我们实现代理方法,实现代理方法
告诉系统我们要让那个控件具有缩放功能,
然后设置视图的缩放比列即可,
81、如何向系统相册保存一张图片
首先获取要保存的图片,然后实现系统写入照片的方法,
UIImageWriteToSavedPhotosAlbum(_imageView.image,self,@selector(image:didFinishSavingWithError:contextInfo:),nil);
必须调用系统指定的方法,然后用指示器告诉用户保存成功和失败
- (void)image:(UIImage*)image didFinishSavingWithError:(NSError*)error contextInfo:(void*)contextInfo
{
if(error) {
//保存失败
[SVProgressHUDshowErrorWithStatus:@"保存失败"];
}else{
//保存成功
[SVProgressHUDshowSuccessWithStatus:@"保存成功"];
}
}
82、如何把下载好的相册保存到自己的相册中
苹果保存图片到自己的相册中有自己的逻辑,先把相册保存到系统中,然后再把相册从系统中,拷贝一份到自己的
相册中
photos框架:专门处理相册
如何学习新的框架:1、学习这个框架中常用的类,怎么知道框架中哪些类常用,
(百度/苹果的官方文档)
photos常用的类:PHPhotosLibrary:相簿(所有相册的集合)
PHAsset:图片(资源文件)
PHAssetCollection :相册
PHAssetCreatRequest:创建,修改,删除图片
PHAssetCollectionResquest:创建,修改删除相册
photos框架使用的规则: 要操纵相册或者相片,必须发送请求
如何了结一个类怎么使用:
1、跳转头文件,查看怎么使用
2、按住option,查看PHPhotosLibrary
业务逻辑:
在相薄中进行
1、创建自己的相册(相册请求类创建相册)
2、创建图片请求
3、添加图片到相册
4、用户授权
83、怎样解决,每次添加图片都会重新创建一个新的相册
通过获取系统相册,然后遍历系统所有相册,看是否有相册和要创建的相册同名
有就返回,没有救不返回,
然后判断系统是否有相册,有相册就创建图片请求
没有救创建相册
84、相册的封装
85、添加上拉刷新,
其实就是添加tableView的底部footerView
86、上拉刷新逻辑
什么时候进行上拉刷新数据
上拉控件,完全显示的时候,才会加载数据
当用户拖动的时候,判断上拉什么时候现实完毕刷新数据
怎样知道是刷新的新数据,必须记录上一页最大的maxTime
记录下来
87、关于下拉悬浮的处理
就是在下拉停止拖动的时候设置下拉偏移量。