《百思不得姐》项目知识点总结

从2月12日开始到3月9日,一个月学习这个项目收获了很多知识点,给自己总结出来,方便以后查看。

  • 1.控制器的view加载完毕,首先在- (void)viewDidLoad方法中添加 下拉刷新 的控件;

    • 1.1将添加下拉刷新控件封装一个函数- (void)setupRefresh,该方法中添加MJRefresh框架的header控件
    • 1.2写一个头部控件调用的刷新方法- (void)loadNewTopics,里面写发送网络请求代码
  • 2.在成功返回的block中调用endRefreshing将Header控件隐藏起来,当然失败一样也要影藏起来;

  • 3.一进来TableView就应该自动刷新,所以在- (void)setupRefresh方法中添加完header控件,就调用它的 beginRefreshing方法,让其自动刷新;

  • 4.利用header的 automaticallyChangeAlpha(YES)属性自动改变header的透明度,让其影藏,解决下图效果问题

  • 5.利用MJRefreshAutoNormalFooter类添加footer控件,一开始设置footer控件hidden属性为YES隐藏;

    • 5.1MJRefreshAutoNormalFooter类的footer是上拉到指定位置自动刷新
    • 5.2 MJRefreshBackFooter类刷新完会有一个回弹的效果
  • 6.上拉刷新加载更多数据,所以将下拉刷新发送网络请求的代码同样复制一份到 - (void)loadMoreTopics方法中,但是加载更多需要下一个的页码参数

网络延迟中一些细节处理

  • 7.网络不好时,上拉加载更多失败了,但是page++了,下次加载就会直接跳过失败那页数据,所以在失败的block中将page—;

  • 8.加入显示处在第5页数据中,先在下拉刷新加载最新数据,但是也有可能失败,一旦下拉刷新page被清空为0了,但现在处在第5页,如果现在上拉刷新加载更多,将会重复加载第0页数据。所以改进办法就是当下拉刷新成功了,才将页码清空为0,将self.page = 0; 放到成功的block中;

  • 9.用户有可能下拉刷新又上拉刷新 例如:现在用户当前处在第5页,先下拉刷新,又上拉刷新,一会下拉刷新的数据回来后,page被清空为0了,之后上拉数据回来,成功后会将第六页数据放到第5页数据后,但是第5页数据被清空了,就讲最前面的0页数据和第6页数据合在一起了。如果上拉数据失败,page—,这样当前page被减为负数,也是有问题。 *两种解决办法

    • (1)控制器增加一个字典成员属性params,只处理最后一次的网络请求,如果当前返回的请求和params中的请求不是同一个请求,直接return
if(self.params != params) return;
复制代码
  • (2)禁止用户同时上拉和下拉刷新,如果发现有一个在刷新,则禁止掉例外一个刷新

  • 10.footer控件永远粘着cell的底部,如果一上来,TableView没有数据,那么会直接显示footer控件。所以创建完footer控件时,默认让其隐藏,同时在numberOfRowInSession中设置如果返回的count==0时隐藏

    复制代码

self.tableView.mj_footer.hidden = (self.topics.count == 0);

- 11.设置TableView内边距的一些代码放在“精华”控制器中不合适,应该放到TableView自己的控制器中,子控制器的代码应该放到子控制器

- 12.在other文件中新建一个保存常量的类(继承NSObject),用来保存一些全局都用到的常量信息
  - 12.1 删除所有内容,导入.h和.m都导入 #import <UIKit/UIkit.h>
  - 12.2 .m中放一些const常量,.h中放一些放常量的引用同时加上 UIKIT_EXTERN

- 13.修改TableView内部的Cell的尺寸,让其左右有间距,需要重写他的`setFrame`方法,只需要设置一次的东西就写在`awakeFromNib(xib)`,或`initWithFrame`(代码)方法中

- 14.将createTtime字符串时间转变为`NSDate`格式的时间
```objc
NSDate *now = [NSDate date]; // 当前时间
NSDateFormat *fmt = [[NSDateFormat alloc] init];
fmt.dateformat = @“yyyy-MM-dd HH:mm:ss”;
NSDate *createtime = [fat dateWithString:topic.create_time];
复制代码
  • 15.两个时间的比较方法
    • (1):返回一个时间间隔(s)
NSTimeInterval delta = [now timeIntervalSinceDate:create]; 
复制代码
  • (2):NSCalendar类,有一个currentCalendar方法获取当前的日历
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger year= [calendar component:NSCalendarUnitYear fromDate:now];
复制代码

其中NSCalendarUnitYear是一个枚举,里面有年、月、日、时、分、秒components:fromDate:同上一样,可以传多个枚举值,返回一个NSDateCompoents,里面放着年、月、日、时、分、秒 时间的比较:

NSDateCompoents cmps =[calendar components:枚举 fromDate:create toDate:now options:0]
复制代码

cmps.year, cmps.month等就是相差的间隔。

  • 16.UITableView的Cell有一个TableView:heightForRowAtIndexPath:方法,直接动态计算出每一个Cell的高度,但是这个方法调用非常频繁,所以将具体计算代码放在这里会影响性能。应该给模型提供一个cellHeight属性,重写该属性的getter方法,将计算的代码放这里。并且加一个if判断,如果_cellHeight没有值,才进行计算,这样就保证只计算一次,提升性能。但是提供这样一个属性暴漏在外面,别人很有可能会修改属性,所以加上readonly。

  • 17.如果一个成员变量加了readonly,又重写了getter方法,那么getter方法中的成员变量就会报错,因为编译器认为有readonly的只生成getter方法,自己又实现了getter方法,意味着成员变量也需要自己实现,所以报错。这时,就需要我们自己再实现成员变量,在.m中加上_cellheight的成员变量。

  • 18.- boundingRectWithSize:options:attributes:context:方法是根据文字的大小、宽度,动态计算出这段文字的高度。

  • 19.iPhone默认是不支持gif图片播放的,必须将一个gif图片解析成n个UIImage对象才能进行播放,用到ImageIO框架

  • 20.imageView的contentMode属性中有一个UIViewContentModeScaleToFit属性,表示,缩放图片比例,在现有的显示尺寸的大小内,保证看到图片的全部。另外UIViewContentModeScaleToFill模式是,等比例伸缩,然后在现有显示尺寸的大小内,显示伸缩后的图片的中间部分,但是剩余的头尾剩余部分也会显示出来,会遮盖其他控件,所以在显示图片的iamgeView右侧栏中间的模式中,勾选Clip Subviews即可将多余的部分裁剪掉。

  • 21.带有图片的段子,为了提高用户体验,在图片没有下载完之前,

    • 1.先显示占位图片;
    • 2.提供一个下载的进度条;
  • 22.屏蔽第三方框架带来的风险,就是自己建立一下类,然后继承自框架的类,这样面向自己类做开发,以后如果不用这个框架了只需要改这个类即可,这样减少不用框架后多处修改代码的风险

  • 23.-(void)UIImageWriteToSavedPhotosAlbum(UIImage *image, id completionTarget, SELcompletionSelector, void *contextInfo ); 用来将图片保存进用户的相册,第一次调用会弹框询问。

  • 24.图片段子中的图片,自定义一个UIView类,继承UIView,提供一个类方法返回一个创建好的UIView, ```objc [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];


- 25.根据模型的内容(图片、声音or视频?),将UIView添加到对应的cell中,所以在模型属性的setter方法中写;

- 26.为了保证只创建一次UIView,Cell来回滚动时可以循环利用,所以采用懒加载,但是控件都是弱指针,代码段执行完控件就死了,所以在懒加载中直接将控件下到contentView中

- 27.图片段子中的图片,需要给自定义的图片View增加一个topic模型,然后在if判断中若为图片段子则将topic模型传递给图片view的模型中,这样view才能拿到数据,设置数据到对应的view中去显示

- 28.如果Cell的尺寸做了修改,Cell内部的子控件frame尺寸不对,则将autoresizingMask属性设置为NO
    self.autoresizingMask = UIViewAutoresizingNone;

- 29.判断gif图片标志的显示或隐藏
```objc
    // 判断GIF是否显示
    NSString *extensionName = topic.large_image.pathExtension;
    self.gifView.hidden = ![extensionName.lowercaseString isEqualToString:@"gif"];
复制代码
  • 30.在不知道图片扩展名的情况下,SDWebImage框架中有一个方法,可以取出图片数据的第一个字节,进行判断,获得图片的扩展名,这种方式是最准确的

  • 31.发布按钮点击后,一进来,几个button在执行动画的过程中,应该让按钮不能被点击,所以在控制器的viewDidLoad方法中设置self.view.userInteractionEnabled = NO; (不响应用户交互事件),动画执行完毕(最后标语落下来时),在setCompetionBlock这个block中恢复view的点击事件;

  • 32.UIWindow有三个级别,Normal < StatusBar < Alert 依次升高。如果想做一个动画,在状态栏提示一些东西,就创建一个Window,设置为状态栏级别,挡住系统自带的状态栏,因为状态栏就是一个StatusBar级别的window。

  • 33.命名规范

    • (1)成员变量访问以下滑线开头;
    • (2)全局变量可以在名称后面加一个下划线与成员变量区分;
    • (3)如果没有任何东西就是局部变量
  • 34.发布按钮,一进来动画在执行的过程中,让下降的按钮应该不能被点击,所以在viewDidLoad中让view.userInteractionEnabled = NO,在动画执行完毕后再恢复能点击,在 setCompletionBlock:^的block中恢复

  • 35.reloadData刷新表格时就会调用数据源的三个方法

   - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
      - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
     - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
复制代码
  • 36.header和cell一样也可以循环利用 dequeueReusableHeaderFooterViewWithIdentifier:利用这个方法从缓存池中找这个标识的headerfooterView,返回一个UITableViewHeaderFooterView

  • 37.从iOS8开始提供了一个自动计算Cell高度尺寸的属性,先给出估算高度,然后让真实高度根据具体尺寸伸缩

    self.tableView.estimatedRowHeight = 44;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
复制代码
  • 38.连续点击两次tabBar自动刷新当前窗口中的TableView,是有通知完成,系统的delegate成为tabBarController的代理,当tabBar被点击时,发出一个通知。对应的TableViewController接到通知,调用自己的头部控件开始刷新

  • 39.UIView没有图片属性,也没有背景图片属性,所以要给UIView添加背景需要调用drawRect:方法画上去

  • 40.监听textFiled的文字改变可以用三种方法:

    • (1)代理 - 成为代理——>遵守协议——>实现方法 (不推荐)
    • (2)通知 有一个UITextFiledDidChangeNotification
    • (3)addTarget textFiled继承自UIControl
  • 41.从iOS7以后

[[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStyleDone target:self action:@selector(cancel)]; 
复制代码

style样式写什么都一样

  • 42.设置导航控制器view上的标题文字大小的两种方式
    • (1)UIViewController被导航控制器包装后拿到titleView属性,自己包装一个UIView,里面放一个Label将文 字调整一下 self.navigationItem.titleView
    • (2)拿到 navigationBar属性,在navigationController的initialize方法中设置
[self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:20]}];
复制代码
  • 43.如果在navigatioController利用appearance分状态修改了UIBarButtonItem的属性,那么在控制器中设置 rightBarButtonItem状的enabled的属性之后,要调用layoutifNeeded函数强制刷新
[self.navigationController.navigationBar layoutIfNeeded];
复制代码
  • 44.UITextView没有占位文字,可以自定义一个继承自UITextView,增加一个placeholder属性的UITextView,方法有两种:

    • (1)实现 - (void)drawRect:(CGRect)rect 将文字画上去
    • (2)给TextView增加一个子控件Label,来显示占位文字,好处是,子控件可以在textView实现滚动效果
  • 45.监听UITextView的文字改变有很多中方法

    • (1)通过代理,有一个TextViewDidChange:方法可以监听文字的改变,但是不推荐这种方法,因为控制器要成为代理来监听控件的改变,高耦合性,占位文字是控件内部的功能,应该由自己来控制或隐藏
    • (2)TextView文字发生改变会发出通知UITextViewDidChangeNotification
  • 46.如果监听了通知,一定要调用dealloc方法,将监听删除

  • 47.文字一旦改变就会调用监听方法,在监听方法中调用setNeedsDisplay方法重新绘制,因为setNeedsDisplay会调用DrawRect:方法,该方法每次进来会将之前的内容擦掉,重新绘制一次

  • 48.UITextView给别人提供一个占位文字的属性,别人很有可能随时更改这个属性值,所以要重写属性的setter方法,时时监听属性的修改,需要重写以下几个方法,同时都要调用setNeedsDisplay方法

    • (1) 重写占位文字的属性方法
    • (2) 重写字体属性的setter方法,因为字体别人也有可能修改,同样也要调用
    • (3) 别人可能通过代码修改text值,所有也要重写setText:方法(调用父类的该方法)
    • (4)别人修改的也有可能是富文本属性AttributedText,所有这个属性也要重写
  • 49.TextView继承UIscrollView,所以他是能滚动的,其中有一个属性alwaysBounceVertical,在竖直方向上有弹簧效果

  • 50.增加的label采用懒加载先确定位置,如果label的宽度确定,高度是要通过文字计算出来,所以在layoutSubviews方法中计算根据文字数量和字体大小确定后的label的尺寸,但是控制器中有可能随时修改这个尺寸和文字,所以要在setter方法中调用setNeedsLayout方法在恰当的时间重新计算更新后的label的尺寸

/**
 *  更新label的尺寸
 */
- (void) layoutSubviews
{
    CGSize size = CGSizeMake( self.width - 2 * self.phLabel.x, MAXFLOAT);
    self.phLabel.size = [self.placeholder boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : self.font} context:nil].size;
}
复制代码
  • 51.setNeedsDisplay会在恰当的时候调用drawRect:方法 setNeedsLayout会在恰当时候调用layoutSubviews方法

  • 52.通过代码设置创建按钮的尺寸和图片的尺寸一样的方法

    • (1)button.size = [UIImage ImageNamed:@“tag_add_icon”].size;
    • (2)取出普通状态下的图片 button.size = [button iamgeForState:UIControlStateNormal].size;
    • (3)获取正在展示的图片 button.size = button.currentImage.size;
  • 53.一旦根控制器modal出一个控制器,就会用presentedViewController属性引用着它。

    • a.presentedViewController -> b a控制器的这个属性可以找到弹出的b控制器
    • b.presentingViewController -> a b控制器的这个属性可以找到谁把他push出来了
  • 54.监听TextFiled的文字改变的三种方法:

    • (1)代理方法,但对中文的支持不好,不推荐
    • (2)通知 UITextFieldTextDidChangeNotification
    • (3)addTarget:方法
  • 55.按钮的contenMode属性用在内部的image身上,对文字的对齐方式不起作用, contentHorizontalAlignment属性,是设置按钮内部文字或图片水平方向的排布

  • 56.右下角的换行不是字符,所以不能通过addTarget:方法中的点击方法监听,要通过代理监听

- (BOOL)textFieldShouldReturn:(UITextField *)textField
复制代码
  • 57.- (void)deleteBackard是监听键盘的删除按键

  • 58.自己定义的Block很容易发生循环引用,所以一定要用弱引用

  • 59.布局控制器view中的子控件位置和尺寸的代码最好放到viewDidLayoutSubviews方法中,因为控制器的view有可能是通过xib、代码、storyboard创建,所以一开始初始化时的尺寸是不准确的。但是当view布局完成后的尺寸是最准确的

  • 60.Xcode中蓝色文件夹表示在项目中真实存在

  • 61.ABS()是取绝对值函数

  • 62.- (void)prepareLayout用来做布局的初始化操作(不建议在 init 方法中进行布局的初始化操作)

  • 63.- (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error;这个方法获取文件大小是可靠的,文件计算不准确

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值