微博项目笔记

微博笔记:

1.LaunchScreen

/*

 *LaunchScreen:替代以前的启动图片

 *好处:

 *1.可以展示更多的内容

 *2.仅仅需要一张大尺寸的图片就好,然后伸缩适应图片

 *

 *启动的优先级:

 *启动图片的优先级低于 < LaunchScreen (图片不适合时记得调一下伸缩)

 *

 * 当模拟器尺寸不对的时候,第一时间找启动图片,模拟器的尺寸由启动图片决定(使用启动图片不用Xib的时候记得调整Info.plist 加载launchScreen的名称删掉)

 

 */

2.-----------------------------

   //显示窗口

     [self.window makeKeyAndVisible];

    //makeKeyAndVisible 等价于,但是application.keyWindow = self.window只读

    //1.application.keyWindow = self.window;

 

   // 2.self.window.hidden = NO;

3viewController的加载顺序——————————————————

  //1.UITabBarController View 是在UITabBarController控制器一创建就加载

 

    //2.UIViewController   的View是在加显示窗口的才加载显示,(用到的才会显示,属于懒加载(需要用到的时候才会加载))

 

4 instancetype————————————————————

//instancetype:默认会识别哪个类和子类调用,默认就会转为对应的类的对象

5.id-----------------------------

 id (不建议使用):

 1.使用这个不能使用点语法

2.所有的Set 和 Get 方法都能使用 ,不能识别出错误

 

6.Dictionary 的新语法

dic[NSForegroundColorAttributeName] = [UIColor orangeColor];

    //上面的等价于下面的着这种方法,键 = Value key的值直接在 UIKIT中找

 

   [dic setValue:[UIColor orangeColor]forKey:NSForegroundColorAttributeName];

7.appearance 的介绍和使用特点————————————

 //appearances什么时候可以获获取外观标识,当这个类遵循UIAppearance协议的时候,比如:UIView

    //获取所有的tabBarItem  appearance:为全局外观的标始(不够严谨,会影响所有遵循UIAppearance协议的)

   // UITabBarItem *item = [UITabBarItem appearance];

    

    //self ->XDTabBarController

    //获取当前类下面的所有TabBarItem

    UITabBarItem *item = [UITabBarItem appearanceWhenContainedIn:self, nil];

    //设置模型的文本属性

    NSMutableDictionary *dic = [NSMutableDictionary dictionary];

    dic[NSForegroundColorAttributeName] = [UIColor orangeColor];

    

    //上面的等价于下面的着这种方法,键 = Value key的值直接在 UIKIT中找

    //[dic setValue:[UIColor orangeColor] forKey:NSForegroundColorAttributeName];

 

    [item setTitleTextAttributes:dic forState:UIControlStateSelected];

//--------------------+(void)load 什么时候调用和作用-------

//什么时候调用:程序一启动的时候就会把所有类加载到内存

//作用:加载所有的类

//+(void)load

//{

//

 

//}

 

//———————+(void)initialize什么时候调用和作用----------

//什么时候调用:初次使用某个类或者子类的时候调用

//作用:初始化类

+(void)initialize

{

}

 

//获取TabBar 全局外观属性,设置外观属性,设置文字属性

 //appearance:是一种协议 只要遵循 :UIAppearance就可以 所以当前的类归自己管理,使用appearanceWhenContainedIn

    UITabBarItem *item = [UITabBarItem appearance];

    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];

    attributes[NSForegroundColorAttributeName] = [UIColor orangeColor];

 

     [item setTitleTextAttributes:attributes forState:UIControlStateSelected];

 

//———————设置中间的按钮的位置

 //设置中间的按钮的位置

    self.plusButton.center = CGPointMake( w * 0.5, h * 0.5);

 

    //self.plusButton.bounds = CGRectMake(0, 0, self.plusButton.currentBackgroundImage.size.width, self.plusButton.currentBackgroundImage.size.height);

 //默认的按钮大小与背景图片一样

 //sizeToFit 会根据你的背景图片 Image和文字计算出最合适的位置

 

        [addButton sizeToFit];

 

//————————item 模型的 求法

//self.items 是UITabBarItem 的模型 ,有多少个子控制器就有多少个Item模型

//————————TitleView 设置为搜索框—————

1.如果要求在左边显示提示文字 ,则要使用可以使用占位符的,用UITextFile 代替 UIsearch ,要设置它的UITextFiled 的左边搜索按钮,则要设置 它的leftView , 但是要求有一定的距离,则先拉伸 ,在让图片自我调节位置。当设置UITextFiled 的上的左右视图时 :leftViewMode 一定要设置它的状态   

//self(  UITextFiled  )

        //initWithImage:图标的大小会默认与图片一样

        UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"searchbar_textfield_search_icon"]];

        imageView.width += 10;

        imageView.contentMode = UIViewContentModeCenter;

        self.leftView = imageView;

        

        //一定要设置,想要显示左边的视图,一定要设置左边的视图模式

 

        self.leftViewMode = UITextFieldViewModeAlways;

 

//————隐藏底部的标签栏————

  //Push 的时候隐藏底部的标签栏

    //hidesBottomBarWhenPushed:的前提条件是,system 自带的才可以使用

 

    self.hidesBottomBarWhenPushed = YES;

//———————————创建XIb initWithNibName的实现步骤

 

 //1.先查看是否有XDOneView.xib的文件

    //2.第二步加载与控制器同名的XDOneViewController.xib 文件

    //创建一个默认几乎的透明的View

    XDOneViewController *one = [[XDOneViewController alloc]initWithNibName:nil bundle:nil];

//等价于,因为init 它的底层会调用 initWithNibName

  XDOneViewController *one = [[XDOneViewController alloc]init];

------------------------------------------------------------------------------------------------------------

//—————统一样式的左右导航按钮的时候———

1.要在继承(UINavigationController)导航控制器d的类中,利用

-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{

if (self.viewControllers.count != 0) {//不是跟视图控制器

        //设置导航栏的内容

        //设置导航控制左右两边的按钮

        //左边的按钮

        //当设置的左边的返回按钮覆盖以后,不能实现滑动返回手势功能

        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemWithImage:[UIImage imageNamed:@"navigationbar_back"] highImage:[UIImage imageNamed:@"navigationbar_back_highlighted"] target:self action:@selector(backToPre) forControlEvents:UIControlEventTouchUpInside];

        

        //右边的按钮

 

        viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonItemWithImage:[UIImage imageNamed:@"navigationbar_more"] highImage:[UIImage imageNamed:@"navigationbar_more_highlighted"] target:self action:@selector(backToRoot) forControlEvents:UIControlEventTouchUpInside];

}

 //    CZLog(@"%s",__func__);

 

    [super pushViewController:viewController animated:animated];

}

#pragma mark 导航控制器左右两边的Item UIBarButtonItem Action

-(void)backToPre

{

    [self popViewControllerAnimated:YES];

}

-(void)backToRoot

{

    [self popToRootViewControllerAnimated:YES];

}

 

2.当返回按钮被覆盖的时候,返回滑动手势则会失效

1.要在继承(UINavigationController)导航控制器d的类中,viewDidLoad中设置它的导航控制器代理

- (void)viewDidLoad {

    [super viewDidLoad];

  

    //保存原来的滑动手势代理

    _popDelegate = self.interactivePopGestureRecognizer.delegate;

    //导航控制器上的代理方法,实现判断是否回到跟控制器

    self.delegate = self;

  

    

 

}

 

//2.调用调用带有展示当前的ViewController 的代理方法,什么时候使用系统的滑动手势代理方法,什么时候不适用

#pragma mark -------popDelegate 

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated

{

    NSLog(@"%@",self.viewControllers[0]);//判断它是哪一个控制器

    if (viewController == self.viewControllers[0]) {//显示的是跟控制器

        //还原滑动返回手势

        self.interactivePopGestureRecognizer.delegate = _popDelegate;

    }else//不显示根视图控制器

    {

        //实现滑动返回功能

        //清空滑动返回收手势代理,就能实现返回滑动功能

        self.interactivePopGestureRecognizer.delegate = nil;

    

    }

 

}

 

------------------------------------------------------------------------------------------------------------

//------------可以循环利用的两个的中, TableView 与 colletionView  

 它们添加内容都是调用ContentView,

//检查是否有新的版本

    //如果有新特性,进入新特性界面

    //还有一定要对CollectionView ,进行LayOut

------------------------------------------------------------------------------------------------------------

    

    //1.获取版当期的版本号

    NSString *currentVersion =  [NSBundle mainBundle].infoDictionary[@"CFBundleVersion"];

    

    //2.获取上一次的版本号

    NSString *lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:XDVersionKey];

    

    //3.判断版本号,是否要新定义

    if ([currentVersion isEqualToString:lastVersion]) {//当前版本号和上一次相同

        

        //创建tabBarController ,把它作为根视图控制器,支持设备旋转

        XDTabBarController  *tabBarController = [[XDTabBarController alloc] init];

            self.window.rootViewController = tabBarController;

        

    }else{//当前版本号和上一次的不相同,要从新特性界面进入

    

        XDNewFeatureController *newFeatureVC = [[XDNewFeatureController alloc] init];

        self.window.rootViewController = newFeatureVC;

        

        //保存当前的版本号,用编号设置

        [[NSUserDefaults  standardUserDefaults]setObject:currentVersion forKey:XDVersionKey];

    

    }

//—————————偏好设置的优点————————

//偏好设置存储的好处

//1.不用自己管理文件名

//2.快速进行键值对存储

 

//———————————OAuth授权———————

OAuth授权:让数据变得更安全

流程:有数据提供商提供一个登陆网站,显示在第三方客户端上

什么时候需要UAuth授权:1.需要获取第三方数据(新浪,腾讯,百度,豆瓣)

                                2.第三方登录

                                 3.第三方分享

注意:并不是任何软件都能OAuth授权,只有成为第三方的开发者,才能UAuth授权

如何成为第三方开发者?

//1.在百度上搜索 微博开放平台

//2.登录自己的微博账号

//3.点击微链接,选择移动开发,实名认证以后,点击继续创建

//4.高级信息中填写OAuth授权设置

//——————OAuth 授权的步骤——————

授权步骤总结:

1.获取未授权的Request Token<进入登陆界面>拼接的时候记得不要留空白

2.获取用户授权的Request Token <点击授权>

3.用授权的 Request Token 换取 Access Token 

(得到这个 Access Token 就相当于得到一个“令牌”,通过此”令牌“请求

就可以拥有资源的网站抓取任意有权限被抓取的资源)

 

access_token:表示哪个软件在哪个用户下的标志符,获取了access_token就可以获取相应的数据提供商提供的数据

uid:表示用户的唯一标识符

 

//———开发步骤———————

1.搭建开发界面

2.展示数据

3.处理对应的业务逻辑

//—————————content-type:响应头的错误----

/*

 "Request failed: unacceptable content-type: text/plain"

 1.AFN通过判断响应头,判断是否有解析数据的方式,content-type: 包含在响应头中,所以要修改AFN,让其包含text/plain解析方式

 

 */

//———KVC的底层

1.一个一个的遍历Key ,查找是否有 SetKey ,如果有的话直接赋值

2.看是否有_key,如果有的话找到直接赋值

3.遍历所有的key,给key 赋值

4.如果key没有赋值,就会报错

 

//————跟服务器打交道

1.向服务器发送请求 -->一般的参照接口文档,跟接口文档打交道,就查阅接口文档(1.请求的Url 2.哪种类型的接口(GET,Post)3.返回的数据格式)

2.服务器响应的数据-->解析数据,设计数据模型—>返回数据转换为模型

3.展示数据,刷新数据

 

//———————使用SDWebImage  的好处和注意点

SDWebImage 的好处:

1.属于异步请求,不会阻塞主线程(界面)

2.自动创建缓存

3.可以让图片循环利用

注意点:因为自动创建缓存,很容易造成内存的警告

解决的方法:

-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application

{

   //停止所有的图片下载

    [[SDWebImageManager sharedManager] cancelAll];

    

    //清空所有缓存

    [[SDWebImageManager sharedManager].imageCache clearMemory];

 

 

}

 

//———下拉刷新数据 ,下拉添加更多的数据

 

 //添加下拉刷新控件

    [self.tableView  addHeaderWithTarget:self action:@selector(loadNewStatus)];

    

    //自动刷新微博数据

    [self.tableView  headerBeginRefreshing];

  //结束下拉刷新

 

        [self.tableView headerEndRefreshing];

     //最新数据的条数

        NSIndexSet *indexSets = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,statuses.count)];

     //把最新的微博插入到前面,一定要数组的形式添加数据

        [self.statuses insertObjects:statuses atIndexes:indexSets];

 

 

        //添加上拉刷新控件

 

    [self.tableView addFooterWithTarget:self action:@selector(loadOtherStatus)];

 

 

    //since_id false int64 若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。

  if (self.statuses.count) {//有微博数据,需要下拉刷新

    params[@"since_id"] = [self.statuses[0]idstr];

    }

 

 //max_id false int64 若指定此参数,则返回ID小于或等于max_id的微博,默认为0。,默认为0

 

1.注意点:一定要记得“-1”把重复的数据去掉

    if (self.statuses.count) {//有数据需要上拉获取(以前)更多的数据

        

 long long max_Id  =[[[self.statuses  lastObject] idstr]longLongValue]-1;

        params[@"max_id"] = [NSString stringWithFormat:@"%lld",max_Id];

        

 

    }

  //结束下拉刷新

 

        [self.tableView footerEndRefreshing];

   //不能使用addObjects: 必须把数组的元素加入

 

        [self.statuses addObjectsFromArray:statuses];

 

//请求数据常规的开发步骤

1.查看接口文档

2.依据参数列表,设置参数模型

3.依据结果列表设置结果模型

4.拿到对应的工具类请求就好

 

//设置软件的消息未读数

//设置应用程序的未读数,记得要注册通知

 

        [UIApplication sharedApplication].applicationIconBadgeNumber =接收到消息数目( result.totalCount);

1. applicationIconBadgeNumber 查看它的头文件 

2.从头文件中可以知道它是对象 注册[UIApplication registerUserNotificationSettings:]

3.在程序的启动页面,AppDelegate 写

//注册微博程序未读消息通知

    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil];

    [application registerUserNotificationSettings:settings];//通过这里可以推出要有UIUserNotificationSettings 对象的属性

 

//点击tabBar Item 的时候 刷新微博 的逻辑 :不要当选中第一个按钮的时候都刷新,当自己想跳转到其他页面,再次点击刚刚的按钮的时候,又刷新,那原来的浏览的消息界面就改变了,所以要满足 两次选中的还是同一个按钮的时候才刷新 index == 0(这是指定) && self.selectedIndex == index

//让程序一直处于运行,在后台播放

 

//在真机的话要记得设置音频会话

[/*

     //混合播放,会把后台的音乐混合播放

     AVF_EXPORT NSString *const AVAudioSessionCategoryAmbient;

     

     //单独播放,会先把后台的音乐先停下来,然后再播放

    AVF_EXPORT NSString *const AVAudioSessionCategorySoloAmbient;

    

   //进入后台就播放

    AVF_EXPORT NSString *const AVAudioSessionCategoryPlayback;

     */

    //在真机的后台播放音乐

    AVAudioSession *session = [AVAudioSession sharedInstance];

    

    //设置会话的类型,可以两种类型一起设置

    [session setCategory:AVAudioSessionCategoryPlayback error:nil];

    [session setCategory:AVAudioSessionCategorySoloAmbient error:nil];

    

    //激活

 

    [session setActive:YES error:nil];

]//这是加载程序的时候就设置

//程序即将失去焦点的时候调用

- (void)applicationWillResignActive:(UIApplication *)application {

    

   //设置播放器

    NSURL *url = [[NSBundle mainBundle] URLForResource:@"一次就好.mp3" withExtension:nil];

    AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];

    //准备播放

    [player prepareToPlay];

    //无限播放

    player.numberOfLoops = -1 ;

    //播放

    [player play];

    

    //记得局部变量都要,强引用

    _player = player;

}

 

//当程序进入后台的时候调用

- (void)applicationDidEnterBackground:(UIApplication *)application {

 

    //开启一个后台任务,时间不确定,优先级比较低,假如系统要关闭应用的时候,系统会优先关闭这个程序

    UIBackgroundTaskIdentifier ID =[application beginBackgroundTaskWithExpirationHandler:^{

        //结束后台的任务

        [application  endBackgroundTask:ID];

    }];

    

    //1.如何提高后台的优先级,欺骗苹果,设置播放程序

    

    //2.苹果系统会检测是否在播放音乐,当没有在播放音乐的时候,系统会关闭程序

    

    //3.微博:在即将失去焦点的时候会播放静音的音乐

 

}

//—————复杂的界面的开发步骤——————

1.按照业务逻辑划分界面的结构(原创,转发,工具条)

2.每一个结构都自定义控件

3.在控件上先把所有划分的结构界面都添加上去

4.计算每个控件的位置,如果以后碰到的内容是根据模型决定的,马上就搞个ViewModel视图模型(模型 + 控件的Frame)

5.模型转视图模型

6.给控件赋值视图模型

7.调节界面(文字和颜色)

 

//UIImageView 的 contentMode

UIViewContentModeScaleToFill,//填充整个控件

UIViewContentModeScaleAspectFit,//按比例缩放,且不会超出控件

UIViewContentModeScaleAspectFill, //按比例缩放,且高度或则宽度有一个不超出控件,然后让图片的中心对齐控件中心

UIViewContentModeCenter,//不会缩放图片,只会把图片的中心点和控件对齐

//-------获取服务器的图片的时候,如果不清晰的话

 http://ww1.sinaimg.cn/thumbnail/61c99730jw1eyndx74f8pj20tz124aik.jpg

 http://ww1.sinaimg.cn/bmiddle

/61c99730jw1eyndx74f8pj20tz124aik.jpg

 

//当记不住Block 的格式时候 在 代码中敲 :inline 就会显示

 

**********************************************************

//当设置复杂的cell还是其他的先要划分结构,有哪几部分组成,划分成子控件(注意点:cell 的初始化 initWithStyle)

1.先搭建框架

2.搭建子类控件

*****************************************************************************************************

//重写创建Cell ,自定义创建cell:使用类方法

+(instancetype)cellWithTableView:(UITableView *)tableView

{

    static NSString *ID = @"cell”;

//放回的cell 是否为闲置

     id cell = [tableView dequeueReusableCellWithIdentifier:ID];

    if (cell == nil) {

  //谁调用就初始化谁的类

      cell = [[self alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];

    }

    

    return cell;

 

}

*****************************************************************************************************

MVVM思想:

/*

 1.cell的高度应该提前计算出来: 当一有数据的时候就要使用VM 设置Cell的大小

 2.cell 的高度 必须计算每个cell的子控件必须frame,才可以确定(类似字体的话,你通过字体的小设置Frame的同时,记得要设置控件的字体)

 2.在cell的setStatus方法计算cell的高度,会比较耗费性能

 

 解决的办法:MVVM思想

 M:模型

 V:视图

 VM:视图模型,(模型中包装模型+模型对应视图的Frame)

 */

/*

 复杂的界面开发步骤:

 1.按照业务逻辑划分结构,(原创,转发,工具条)

 2.每一个结构,都自定义一个控件

 3.在控件上先把所有划分的结构添加上去

 4.计算每个控件的位置,如果碰见的内容是根据模型决定的,马上定义一个ViewModle(模型+模型的大小)

 5.模型转视图模型

 6.赋值

7.调节界面(文字大小,颜色)

8.一个结构一个结构的处理

 

 */

/*

1.可以直接传递数据,确定数据的放置的位置

2.MVVM:如果一个控件循环利用,可以避免多次计算控件的Frame

*/

*****************************************************************************************************

常用的图片大小

1.导航条的 高度:64点 @2x :128 @3x : 192 

2.tabBar的高度: 49点

3.导航条的子控件和tabBar 的子控件 Or 工具条的高度:35

*****************************************************************************************************

开发中注意的事项

1.UIView 是设置不了 图片的,那先要转变成:UIImageView 这可以添加图片,但是要注意,记得设置交互

self.userInteractionEnabled = YES;

2.设置每一个cell 间的间距,不可以整个cell设置因为没有设置它的 X Y 是不确定的,所以可以设置cell 中的原创微博 的高度 下移 10 个间距 ,在设置tableView 的背景颜色就好

*****************************************************************************************************

时间的业务逻辑:(使用的框架为:NSDate+MJ

//设置时间格式(由于使用点语法获取数据的,所以要重新设置Get方法)判断的技巧:不要从小的开始判断,要先判断大的,再依次判断小的

-(NSString *)created_at

{

    // Sat Mar 26 16:05:03 +0800 2016 微博给我们的时间格式

    //1.先要把字符串转化成 NSDate

    //转换 EEE MMM d HH:mm:ss Z yyyy

    //日期格式转换

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

    formatter.dateFormat = @"EEE MMM d HH:mm:ss Z yyyy ";

    NSDate *creat_time = [formatter dateFromString:_created_at];

    if ([creat_time isThisYear]) {//今年

        //两天前

        if ([creat_time isToday]) {//今天

            NSDateComponents *cmp = [creat_time deltaWithNow];

            if (cmp.hour >= 1) {

                return [NSString stringWithFormat:@"%ld小时前",cmp.hour];

            }else if(cmp.minute > 1)

            {

                return [NSString stringWithFormat:@"%ld分钟前",cmp.minute];

            }else

            {

                return @"刚刚";

            }

            

        }else if ([creat_time isYesterday])

        {//昨天

            formatter.dateFormat = @"昨天 HH:mm";

            return [formatter stringFromDate:creat_time];

        

        }else

        {//前天

            formatter.dateFormat = @"MM-dd HH:mm";

            return [formatter stringFromDate:creat_time];

        }

        

   

    }else{//不是今年

         formatter.dateFormat = @"yyyy-MM-dd HH:mm";

        return [formatter stringFromDate:creat_time];

    }

    

    return _created_at;

}

*****************************************************************************************************

图片的contentMode经常使用的介绍

   /**

         * UIViewContentModeScaleToFill :将整个图片压缩到适合控件的大小

         UIViewContentModeScaleAspectFit :按比例缩放到不超出边框

         UIViewContentModeScaleAspectFill:按比例缩放到到一边(宽或高)不超出边界合适就不在改变

        UIViewContentModeCenterview 与图片的中心点对齐,不会居中

         *

         */

        imageView.contentMode = UIViewContentModeScaleAspectFill;

//把多余的截掉

imageView.clipsToBounds = YES;

*****************************************************************************************************

//九宫格的布局

1.先求总体的Frame

   //配图

    if (_status.pic_urls.count) {

        CGFloat photosX = textX;

        CGFloat photosY = CGRectGetMaxY(_orignalTextFrame) + MDStatusCellMargin;

        CGSize photosSzie = [self setPhotosSizeWithCount:_status.pic_urls.count];

        _orignalPhotosFrame =(CGRect){{photosX,photosY},photosSzie};

        

        originalH = CGRectGetMaxY(_orignalPhotosFrame) + MDStatusCellMargin;

 

    }

//计算大小的方法setPhotosSizeWithCount

-(CGSize)setPhotosSizeWithCount:(NSInteger)count

{

   //配图的列数

    NSInteger cols = count == 4?2:3;

    //配图行数(这是有计算公式的):行数 = (总数 - 1/列数 +1

    NSInteger rols = (count - 1) / cols + 1;

    CGFloat photosWH = 70;

    CGFloat photosW = photosWH * cols + (cols - 1) * MDStatusCellMargin;

    CGFloat photosH = photosWH * rols  + (rols - 1)* MDStatusCellMargin;

    CGSize photosSie = CGSizeMake(photosW, photosH);

    return photosSie;

 

}

//计算九宫格内部布局

-(void)layoutSubviews

{

    [super layoutSubviews];

    CGFloat x = 0;

    CGFloat y = 0;

    CGFloat w = 70;

    CGFloat margin = 10;

    CGFloat h = 70;

    int col = 0;

    int rol = 0;

    int cols = _pic_urls.count == 4?2:3;

    

    //计算要显示的图片的Frame

    for (int i = 0; i< _pic_urls.count; i++) {

        col = i % cols;

        rol = i / cols;

        UIImageView *imageV = self.subviews[i];

        x = col * (margin + w);

        y = rol * (margin + h);

        imageV.frame = CGRectMake(x, y ,  w, h);

    }

 

}

*****************************************************************************************************

//图片浏览器设置

//添加九个配图控件(要把传过来,利用属性传值)

-(void)setUpAllChildVC

{

    //九宫格中

    for (int i = 0; i < 9 ; i++) {

        UIImageView *imageView = [UIImageView alloc].init;

        /**

         * UIViewContentModeScaleToFill :将整个图片压缩到适合控件的大小

         UIViewContentModeScaleAspectFit :按比例缩放到不超出边框

         UIViewContentModeScaleAspectFill:按比例缩放到到一边(宽或高)不超出边界合适就不在改变

        UIViewContentModeCenterview 与图片的中心点对齐,不会居中

         *

         */

        //添加点图片手势按钮

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)];

        imageView.tag = i;

        //当使用UIImageView的时候,记得设置图片的交互

        imageView.userInteractionEnabled = YES;

        

        [imageView addGestureRecognizer:tap];

        imageView.contentMode = UIViewContentModeScaleAspectFill;

        //把超出边框的图片去掉

        imageView.clipsToBounds = YES;

        [self addSubview:imageView];

    }

 

}

//添加点图片手势按钮

-(void)tapGesture:(UITapGestureRecognizer *)tap

{

     //在手势的图片添加Tag,这可以知道获取的是第几张图片(通过手势可以获取点击的图片)

    UIImageView *imageV = (UIImageView *) tap.view;

    //点击图片的时候调用

    //创建图片浏览器

    int i = 0;

    NSMutableArray *array = [NSMutableArray array];

    for (MDPhotos *photos in _pic_urls) {

        //MDphotos 转换成 MJphoto

        //MJPhoto.h 的文件中 ,要实现的属性有

        //1.@property (nonatomic, strong) NSURL *url;

        //2.@property (nonatomic, strong) UIImageView *srcImageView; // 来源view(你点击那个图片)

        //3.@property (nonatomic, assign) int index; // 索引

        MJPhoto *mjPhotos = [[MJPhoto alloc] init];

        //图片不清晰时,可以键连接的改一下

        NSString *urlString = photos.thumbnail_pic.absoluteString;

        urlString = [urlString stringByReplacingOccurrencesOfString:@"thumbnail" withString:@"bmiddle"];

        mjPhotos.url = [NSURL URLWithString:urlString];

//        NSLog(@"%@",photos.thumbnail_pic);

        mjPhotos.index = i ;

        mjPhotos.srcImageView = imageV;

        [array addObject:mjPhotos];

        i ++ ;

    }

    

    MJPhotoBrowser *browser = [[MJPhotoBrowser alloc] init];

    /*MJ头文件提示要实现的,以后使用框架的时候,要看头文件

     // 所有的图片对象(MJPhoto)

     @property (nonatomic, strong) NSArray *photos;

     // 当前展示的图片索引

     @property (nonatomic, assign) NSUInteger currentPhotoIndex;

     */

    browser.photos = array;//所有图片对象

    browser.currentPhotoIndex = imageV.tag ;

    //以后看到要显示到主窗口的 可以 考虑框架是否有 show(看框架头文件)

    [browser show];

    

 

 

 

}

*****************************************************************************************************UITextView 中输入的字体设置和水印的文字大小一样(textView 输入的位置x= 5,y = 8)

UITextView 系统没有默认设置self.font 

通过设置:

-(instancetype)initWithFrame:(CGRect)frame

{

    if (self = [super initWithFrame:frame]) {

        self.font = [UIFont systemFontOfSize:13];

       //self.placeHolderLable.font = font;  不要在这里设置,当外界改变(textView)的时候,也会改变

    }

    return self;

}

//再重写setFont设置placeHolderLable.font 可以跟着外面 改变

-(void)setFont:(UIFont *)font

{

    [super setFont:font];

    self.placeHolderLable.font = font;

 //避免在输入信息后在设置字体,这样字体的大小不符合lable Frame

 

    [self.placeHolderLable sizeToFit];

 

}

*****************************************************************************************************

becomeFirstResponder //变成第一响应,

resineFirstResponder  //放弃第一响应,

响应机制多用在获取(或放弃)键盘行为

******************************************************************************

判断是否有文本输入的时候可以使用通知

 //监听文本的输入(通知)

    /**

     *1.addObserver:需要监听的对象

     2.name:监听通知的名称

     3.object:监听谁发送通知 nil:谁发送都监听

     设置通知,要把它移除

     UITextViewTextDidChangeNotification:这是监听输入名称(需要记住的)

     *

     */

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChange) name:UITextViewTextDidChangeNotification object:nil];

}

-(void)textChange

{    //监听是否有文本输入

    if (_textView.text.length) {//有文本输入

        _textView.hiddlePalceHolder = YES;   

    }else

    {//没有文本输入

        _textView.hiddlePalceHolder = NO;

    }

}

-(void)dealloc

{    //移除通知

    [[NSNotificationCenter defaultCenter]removeObserver:self];

}

*****************************************************************************

 //设置图片的大小(有的图片上传的时候要大小限定)

CGFloat compressionQuality 这是图片压缩系数

 

    UIImageJPEGRepresentation(<#UIImage *image#>, <#CGFloat compressionQuality#>)

//这是压缩图格式

  NSData *data =  UIImagePNGRepresentation(image);

*****************************************************************************

   //自动布局行高

 

    self.tableView.rowHeight = UITableViewAutomaticDimension;

tableView:dequeueReusableCellWithIdentifier

 1.storyBoard 其实就是内部会帮你注册cell

     2.在ViewDidLoad 使用了(forIndexPath:)没有使用storyBoard ,要自己手动创建 [self.tableView registerClass:[自己的创建cell类 class] forCellReuserIdentifer:ID ];

 

   forIndexPath:不能使用自己创建的cell

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath];

    /*1.先从缓存池中取出数据

      2.判断Cell 有没有注册,有的话,直接创建cell

    3.没有创建就返回NIL

原文地址:https://www.cnblogs.com/meixian/p/5370943.html