IOS 项目环境部署

当我们开发一个新的app的时候,新建一个项目之后 要对这个项目的基本环境进行设置,
首先是启动图片 和app图标(桌面显示的那个)

  • 设置启动图片有两种方式
  1. LaunchScreen
  2. LaunchImage
    优先级:LaunchScreen > LaunchImage
    在xcode配置了,不起作用 1.清空xcode缓存 2.直接删掉程序 重新运行
    如果是通过LaunchImage设置启动界面,那么屏幕的可视范围由图片决定
    注意:如果使用LaunchImage,必须让你的美工提供各种尺寸的启动图片

LaunchImage 各种图片:

  • iPhone Portrait ios 5,6

  • 1x320 * 480

  • 2x640 * 960

  • Retina 4640 * 1136

  • iPhone Portrait iOS 8,9

  • Retina HD 5.5''1242 * 2208

  • Retina HD 4.7''750 * 1334

  • 5.8: 2436 * 1125 @3x

  • iPhone Landscape iOS 8,9

  • Retina HD 5.5''2208 * 1242

  • iPhone Portrait iOS 7-9

  • 2x640 * 960

  • Retina 4:*640 1136

  • iPhone Portrait iOS 12 +
    iPhone XR828px x 1792px
    iPhone XS Max: 1242px x 2688px

  • iPhoneLandscape iOS 12 +
    iPhone XR792px * 828px
    iPhone XS Max: 2688px * 1242px

/****************Ipad********************/

iPad Portrait iOS 7,8

1x 768 × 1024 pixels

2x 1536 × 2048 pixels

** iPad Landscape iOS 7,8**

1x LaunchImage.png 1024 × 768 pixels

2x LaunchImage@2x.png 1536 × 2048 pixels

LaunchScreen:Xcode6开始才有

LaunchScreen好处:
1.自动识别当前真机或者模拟器的尺寸
2.只要让美工提供一个可拉伸图片
3.展示更多东西
LaunchScreen底层实现:把LaunchScreen截屏,生成一张图片.作为启动界面


项目架构

项目架构(结构)搭建:主流结构(UITabBarController + 导航控制器)
-> 项目开发方式 1.storyboard 2.纯代码
确定项目主架构 是用代码还用storyboard,

  • 程序启动的过程
    1.先执行main函数->UIApplicationMain下一步 创建UIApplication(1.打开网页,发短信,打电话 2.设置应用程序提醒数字 3.设置联网状态 4.设置状态栏)
    2.创建AppDelegate代理对象,并且成为UIApplication代理,(监听整个app生命周期,处理内存警告)
    3.开启主运行循环,保证程序一直运行(runloop:每一个线程都有runloop,主线程有一个runloop自动开启)
    4.加载info.plist,判断是否指定了main.storyboard,如果指定,就会去加载

    1.创建窗口
    2.设置根控制器
    3.显示窗口

  • 如果我们使用代码方式, 首相要在这个appdelegate.m里面手动更改系统的跟控制器
// 程序启动的时候就会调用
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //1.创建主窗口
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    
    //2.更改跟控制器
    
    UITabBarController *taBarController = [[UITabBarController alloc] init];
    self.window.rootViewController = taBarController;
    //添加子控制器

    //3. 显示主窗口
    [self.window makeKeyAndVisible];
    return YES;
}
  • 添加tabar控制器的子控制器,设置属性的时候
    问题:
    1.选中的图片被渲染
    2.选中标题颜色:黑色 标题字体大
    3.发布按钮显示不出来
    //精华
    essenceNav.tabBarItem.title = @"精华";
    essenceNav.tabBarItem.image = [UIImage imageNamed:@"imageName"];
    essenceNav.tabBarItem.selectedImage = [UIImage imageNamed:@"imageName"];
    //新帖
    newNav.tabBarItem.title = @"新帖";
    newNav.tabBarItem.image = [UIImage imageNamed:@"imageName"];
    newNav.tabBarItem.selectedImage = [UIImage imageNamed:@"imageName"];

这是因为Xcode自动帮我们把图片渲染,这里我们改变他的渲染方式,
可以定义一个UIImage的分类:

+ (instancetype)imageOriginalWithImageName:(NSString *)imageName
{
    UIImage *image = [UIImage imageNamed:imageName];
    return [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}

处理Tabbar颜色和字体

在自定义的Tabbarcontroller的load方法

/ 只会调用一次
+ (void)load
{
//    UITabBarItem *item = [UITabBarItem appearanceWhenContainedInInstancesOfClasses:<#(nonnull NSArray<Class<UIAppearanceContainer>> *)#>];io9
    
    UITabBarItem *item = [UITabBarItem appearanceWhenContainedIn: self, nil];
    // 设置按钮选中标题的颜色:富文本:描述一个文字颜色,字体,阴影,空心,图文混排
    // 创建一个描述文本属性的字典
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    dic[NSForegroundColorAttributeName] = [UIColor blackColor];
    [item setTitleTextAttributes:dic forState:UIControlStateSelected];
    
    //设置字体大小// 设置字体尺寸:只有设置正常状态下,才会有效果
    NSMutableDictionary *fontDic = [NSMutableDictionary dictionary];
    fontDic[NSFontAttributeName] = [UIFont systemFontOfSize:8];
    [item setTitleTextAttributes:fontDic forState:UIControlStateNormal];
    
}

如果前一天有没有做完的地方我们 可以使用

#warning TODO

来提示我们有哪些地方没有做的

发布按钮的图片不显示 或者现实的的位置不对

  1. 选中按钮的图片被渲染 -> iOS7之后默认tabBar上按钮图片都会被渲染 1.修改图片 2.通过代码

  2. 选中按钮的标题颜色:黑色 标题字体大 -> 对应子控制器的tabBarItem

  3. 发布按钮显示不出来 分析:为什么其他图片可以显示,我的图片不能显示 => 发布按钮图片太大,导致显示不出来

  4. 图片太大,系统帮你渲染 => 能显示 => 位置不对 => 高亮状态达不到
    publishVc.tabBarItem.imageInsets = UIEdgeInsetsMake(6, 0, -6 , 0);

解决:不能修改图片尺寸, 效果:让发布图片居中

自定义tabbar

- (UIButton *)plusBtn
{
    if (_plusBtn == nil) {
        UIButton *pBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        [pBtn setImage:[UIImage imageOriginalWithImageName:@"imageName"] forState:UIControlStateNormal];
        [pBtn setImage:[UIImage imageOriginalWithImageName:@"imageName"] forState:UIControlStateHighlighted];
        [pBtn sizeToFit];
        [self addSubview:pBtn];
        _plusBtn = pBtn;
    }
    return _plusBtn;
}

- (void)layoutSubviews
{
    [super layoutSubviews];
    
    //调整tabbarbutton的尺寸位置
    CGFloat btnW = self.bounds.size.width / (self.items.count+1);
    CGFloat btnH = self.bounds.size.height;
    CGFloat btnX = 0;
    int i = 0;

    for (UIView *subView in self.subviews)
    {
        if ([subView isKindOfClass:NSClassFromString(@"UITabBarButton")])
        {
            if (i == 2)
            {
                i+=1;
            }
            btnX = btnW * i;
            subView.frame = CGRectMake(btnX, 0, btnW, btnH);
            i ++;
        }
    }
    self.plusBtn.center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
    
    
    
}


/******************/
- (void)setTabbar
{
    BDJTarbar *tabbar = [[BDJTarbar alloc] init];
    [self setValue:tabbar forKeyPath:@"tabBar"];
}

抽取UIView的分类


- (void)setX:(CGFloat)x
{
    CGRect myFrame = self.frame;
    myFrame.origin.x = x;
    self.frame = myFrame;
    
}
- (CGFloat)x
{
    return self.frame.origin.x;
}


-(void)setY:(CGFloat)y
{
    CGRect myFrame = self.frame;
    myFrame.origin.y = y;
    self.frame = myFrame;
}

- (CGFloat)y
{
    return self.frame.origin.y;
}


-(void)setWidth:(CGFloat)width
{
    CGRect myFrame = self.frame;
    myFrame.size.width = width;
    self.frame = myFrame;
}
- (CGFloat)width
{
    return self.frame.size.width;
}
-(void)setHeight:(CGFloat)height
{
    CGRect myFrame = self.frame;
    myFrame.size.height = height;
    self.frame = myFrame;
}
- (CGFloat)height
{
    return self.frame.size.height;
}

- (void)setCenter:(CGPoint)center
{
    self.center = center;
}
- (CGPoint)center
{
    return self.center;
}

- (void)setCenterX:(CGFloat)centerX
{
    CGPoint myCenter = self.center;
    myCenter.x = centerX;
    self.center = myCenter;
}

- (CGFloat)centerX
{
    return self.center.x;
}


- (void)setCenterY:(CGFloat)centerY
{
    CGPoint myCenter = self.center;
    myCenter.y = centerY;
    self.center = myCenter;
}
- (CGFloat)centerY
{
    return self.center.y;
}

设置一个pch头文件的

在other里面找到pch


屏幕快照 2019-10-12 上午10.51.16.png

然后在在bulid setting里面打开prefix header

屏幕快照 2019-10-12 上午10.52.42.png

这个路径项目文件夹/子路径/BuDeJieHeader.pch这里的子路径就是你的pch所在的路径,也可以用简单方法直接拖动.pch文件到这个里面就会生出全路径 ,然后自己根据需要的进行删除。

设置导航条的按钮

在进行设置之前,我们要先区分好几个常用的概念
UIBarButtonItem:描述按钮具体的内容
UINavigationItem:设置导航条上内容(左边,右边,中间)
tabBarItem: 设置tabBar上按钮内容(tabBarButton)

由于设置的UIBarButtonItem方法相同,所以我们可以创建一个UIBarButtonItem的分类用于快速创建Item。

  • 设置navigationbarItem
 UIButton *leftBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [leftBtn setImage:[UIImage imageNamed:@"ImageName"] forState:UIControlStateNormal];
    [leftBtn setImage:[UIImage imageNamed:@"ImageName"] forState:UIControlStateHighlighted];
    [leftBtn addTarget:self action:@selector(leftAction) forControlEvents:UIControlEventTouchUpInside];
    [leftBtn sizeToFit];
    UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithCustomView:leftBtn];
    self.navigationItem.leftBarButtonItem = leftItem;

//右边的按钮分类方法
    self.navigationItem.rightBarButtonItem = [UIBarButtonItem itemWithImage:[UIImage imageNamed:@"ImageName"] hightImage:[UIImage imageNamed:@"ImageName"] target:self action:@selector(leftAction)];
    
    //标题
    self.navigationItem.titleView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ImageName"]];

处理导航条标题

+ (void)load
{
    UINavigationBar *navBar = [UINavigationBar appearanceWhenContainedIn:self, nil];
    //ios 之后推荐使用appearanceWhenContainedInInstancesOfClasses
    
    //只要通过模型进行设置,都是使用富文本进行设置
    
    //设置标题
    NSMutableDictionary *titleDic = [NSMutableDictionary dictionary];
    
    titleDic[NSFontAttributeName] = [UIFont systemFontOfSize:20];
    [navBar setTitleTextAttributes:titleDic];
    
    // 设置导航条背景图片
    [navBar setBackgroundImage:[UIImage imageNamed:@"imageName"] forBarMetrics:UIBarMetricsDefault];
 
}

设置导航控制器的跳转逻辑

再有tabbar的时候我们跳转之后需要净底部的tabbar隐藏 然后返回的时候 还需要将它显示出来。

SettingTVController *settingTVC = [[SettingTVController alloc] init];
    //必须在跳转之前设置
    settingTVC.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:settingTVC animated:YES];

  • 统一设置返回按钮
//在自定义的navigationController里面重写push方法
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    
    
    if (self.childViewControllers.count>0) //非根控制器
    {
        viewController.hidesBottomBarWhenPushed = YES;

        viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem backItemWithImage:[UIImage imageNamed:@"imageName"] hightImage:[UIImage imageNamed:@"imageName"] target:self action:@selector(back) title:@"返回"];
    }
    [super pushViewController:viewController animated:YES];
}

- (void)back
{
    [self popViewControllerAnimated:YES];
}
  • 滑动返回
    如果我们自定义了返回的按钮的话 系统自定华东返回手就会失效,
    这个时候我们需要手动的打开代理方法UIGestureRecognizerDelegate

设置方法 self.interactivePopGestureRecognizer.delegate = self;
这时候我们需要实现一个代理方法,如果不实现的话的,当childViewController的个数为一个的时候会就会导致我们的程序进入假死状态,程序还在运行,但是页面已经不可以动了

@interface MyNavigationController ()<UIGestureRecognizerDelegate>
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.interactivePopGestureRecognizer.delegate = self;
}
#pragma mark  - UIGestureRecognizerDelegate -

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(nonnull UITouch *)touch
{
    return self.childViewControllers.count> 1;
}
  • 如果我们想要全屏滑动都可以返回的话,就不能用系统的手势,因为他只有在靠近左边的时候才可以返回,
    这个时候我们首先要做的就将系统的手势交互关掉
   // 禁止之前手势
    self.interactivePopGestureRecognizer.enabled = NO;

打印self.interactivePopGestureRecognizer
可以显示以下信息

<UIScreenEdgePanGestureRecognizer: 0x10121fb60;
     state = Possible; delaysTouchesBegan = YES;
     view = <UILayoutContainerView 0x101218390>;
     target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x10121fa20>)>>

自定义个滑动手势,但是手势的事件处理还是用原来的方法,这个时候我们就可以使用系统的打印出来的信息

 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer  alloc] initWithTarget:self.interactivePopGestureRecognizer.delegate action:@selector(handleNavigationTransition:)];
    [self.view addGestureRecognizer:pan];

Cocoapods的安装

因为mac都是自带ruby的所以我们只需要根据下面的步骤来就可以了

1.先升级Gem
    sudo gem update --system
2.切换cocoapods的数据源
    【先删除,再添加,查看】
    gem sources --remove https://rubygems.org/
    gem sources -a https://ruby.taobao.org/ (淘宝已经不更新了,所以这个不可以使用了,我们可以使用,下面这个)
    gem sources --add https://gems.ruby-china.com #添加国内镜像源
    gem sources -l//查看数据源
3.安装cocoapods
    sudo gem install cocoapods
    或者(如10.11系统)sudo gem install -n /usr/local/bin cocoapods
4.将Podspec文件托管地址从github切换到国内的oschina
    【先删除,再添加,再更新】
    pod repo remove master
    pod repo add master http://git.oschina.net/akuandev/Specs.git
    pod repo add master https://gitcafe.com/akuandev/Specs.git
    pod repo update
5.设置pod仓库
  pod setup
setup这一步会很慢或者无限卡 Setting up CocoaPods master repo,这是因为要在github下载代码,我这一步一直有问题,查询网上都说要将specs仓库镜像换成gitcafe上的镜像或者是 oschina 上的镜像即:

 pod repo remove master 
$ pod repo add master https://git.coding.net/CocoaPods/Specs.git 
//或者  pod repo add master https://git.oschina.net/akuandev/Specs.git
但是执行 pod repo remove master之后老是提示[!] repo master does not exist;然后执行 pod repo add master 
https://git.coding.net/CocoaPods/Specs.git
之后又会提示[!] To setup the master specs repo, please run pod setup. 
然后就无限卡死这两步,不知道是因为cocoapods版本的问题还是网络的问题,
最后直接手动将代码git到本地得以解决问题:
 git clone https://git.coding.net/CocoaPods/Specs.git ~/.cocoapods/repos/master
git完成之后如下:
屏幕快照 2019-10-15 下午1.39.20.png
1、sudo gem update --system
2、gem install cocoapods
6.测试
    【如果有版本号,则说明已经安装成功】
    pod --version
7.利用cocoapods来安装第三方框架
    01 进入要安装框架的项目的.xcodeproj同级文件夹
    02 在该文件夹中新建一个文件podfile (cd到当前工程的文件夹 在终端使用touch Podfile命令创建出一个文件,然后用文本编辑打开)
    03 在文件中告诉cocoapods需要安装的框架信息
        a.该框架支持的平台
        b.适用的iOS版本
        c.框架的名称
        d.框架的版本

具体使用:
cd 项目路径
pod init #创建默认的 Podfile(可跳过)
vim Profile #编辑(没有会创建)Profile配置文件
pod install #安装或删除第三方库
pod install --no-repo-update #安装第三方库,不更新本地索引
pod update #更新到最新版本或指定版本
例如:
platform :ios, '8.0'
pod 'SDWebImage', '~> 5.0'

platform :ios, '8.0' #支持的iOS版本
target 'Demo' do  #指定的项目
  pod 'AFNetworking'  #要添加的第三方库名称及指定版本
end

8.安装
pod install --no-repo-update下载不需要更新pod
pod update --no-repo-update
如果想搜索的话可以使用 pod search XXX
9.说明
platform :ios, '8.0' 用来设置所有第三方库所支持的iOS最低版本
pod 'SDWebImage','~>2.6' 设置框架的名称和版本号
版本号的规则:
'>1.0'    可以安装任何高于1.0的版本
'>=1.0'   可以安装任何高于或等于1.0的版本
'<1.0'    任何低于1.0的版本
'<=1.0'   任何低于或等于1.0的版本
'~>0.1'   任何高于或等于0.1的版本,但是不包含高于1.0的版本
'~>0'     任何版本,相当于不指定版本,默认采用最新版本号

10.使用pod install命令安装框架后的大致过程:

01 分析依赖:该步骤会分析Podfile,查看不同类库之间的依赖情况。如果有多个类库依赖于同一个类库,但是依赖于不同的版本,那么cocoaPods会自动设置一个兼容的版本。
02 下载依赖:根据分析依赖的结果,下载指定版本的类库到本地项目中。
03 生成Pods项目:创建一个Pods项目专门用来编译和管理第三方框架,CocoaPods会将所需的框架,库等内容添加到项目中,并且进行相应的配置。
04 整合Pods项目:将Pods和项目整合到一个工作空间中,并且设置文件链接。

- 有一些框架是不支持pods,要在添加之前查看一下how to use有没有说明,
或者到框架文件里面查看有没有podspec后缀的文件有的话基本可以使用

CocoaPods卸载;

终端使用

sudo gem uninstall CocoaPods #卸载CocoaPods

AFNetworking 使用

如果我们请求的时候出现这个错误的话:unacceptable content-type: text/html" 响应头

客户端从服务情请求的数据 要遵守http协议
请求 分为请求头 请求体
头里面会告诉服务器 客户端支持那些格式,
请求体 一般是在post里面的才有的,把参数发到请求体里面
响应 包含相应头和响应体,响应头里面就有content-type
他是用来描述服务器给你的数据的格式
返回的数据就在响应体里面。
我们那要做的就是让afn接受content-type这种格式
我们来改afn到他的给他添加进去 text/html解析模式,但是要注意,一定是你的数据本身就是json但是服务器的响应头显示的是text/html。

图片设置圆角,

在ios9 之前如果我们直接对layer的属性进行设置的话,图片过多会造成 页面卡顿的效果,所以一般都是对图片进行处理

   // 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();

            self.iconView.image = image;

如果是iOS9之后,设置头像圆角,iOS9苹果修复,不会出现卡顿的文图

    _iconView.layer.cornerRadius = 30;
    _iconView.layer.masksToBounds = YES;

tableViewCell的分割线

当我定义完一个cell,进行展示的时候我们会发现,cell的分割线在前面有一点距离
elf.tableView.separatorInset
处理cell分割线
1.自定义分割线
比如弄一个UIView加到上面去

2.系统属性(iOS8才支持)
self.tableView.separatorInset = UIEdgeInsetsZero;
在cell的初始化方法还要设置
self.layoutMargins = UIEdgeInsetsZero;
因为iOS8 之后xcode就自动给这些view割伤contentmargin。
这只方式可以实现分割线沾满屏幕,但是条件是要最低支持iOS才可以。

3.万能方式
重写在cell的setFrame方法

- (void)setFrame:(CGRect)frame
{
      frame.size.height - =1;
      [super setFrame:frame];
}

请求指示器 提示用户正在加载的信息

这个项目使用SVProgressHUD可以在pod直接引入,也可以到github上面下载引入到项目中
请求的时候使用

[SVProgressHUD showWithStatus:@"正在加载ing....."];

请求结束或者 界面消失的时候

// 销毁指示器
    [SVProgressHUD dismiss];

command+option+回车可以在xib中让label的title文字换行

防止图片拉伸变形,如按钮的背景图片

屏幕快照 2019-10-21 上午11.21.51.png

这种纯色的,或者是那种只有边框的我们最好只拉伸他的中间部分

 UIImage *image = [UIImage imageNamed:@"imageName"];
    
  image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];

使用xib定义的View尺寸 一般不可以直接设置,如果我们要重新设置的话

1.一个view从xib加载,需不需在重新固定尺寸 一定要在重新设置一下
2.在viewDidLoad设置控件frame好不好,开发中一般在viewDidLayoutSubviews布局子控件

处理文本占字符颜色

越复杂的东西越要封装,
当我们的额设置的东西只要一次的时候,而且使用的xib我们可以在aweakFromNib中设置,
当我们找这个占字符的先去头文件查找,attributePlaceholderString

NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    dic[NSForegroundColorAttributeName] = [UIColor whiteColor];
    
    self.attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.placeholder attributes:dic];
  • 快速设置占字符颜色

我们可以使用小面包将页面分析,查看textfied的内容,可以看到
屏幕快照 2019-10-22 上午11.07.31.png

这是看可以看懂field的内部,这是我们可以通过kvc进行设置。但是需要知道属性名字,首先,要获取属性名,1可以通过runtime来打印,2,可以用断点,用断点我们可以查看到


屏幕快照 2019-10-22 上午11.17.50.png
屏幕快照 2019-10-22 上午11.18.21.png

他有一个placeholderLabel的属性
这时候我们就可以利用KVC进行设置

 UILabel *placeholderLabel = [self valueForKey:@"placeholderLabel"];
    placeholderLabel.textColor = [UIColor whiteColor];

如果我们想以后都使用可以自定义一个分类

.h
@property UIColor *placeholderColor;

.m
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
    UILabel *placeholderLabel = [self valueForKey:@"placeholderLabel"];
    placeholderLabel.textColor = placeholderColor;
}
- (UIColor *)placeholderColor
{
    return nil;
}
  • runtime设置
    使用上面的设置方式,要特别注意设置的顺序需要先设置占位文字,在设置颜色,因为这个label是懒加载,如果我们没有设置文字的话,就为nil这时候我们设置颜色是没有效果的。所以我门完善一下。使用runtime。修改placeholder的set方法,和我们自己的设置的方法交换实现.
+ (void)load
{
    // setPlaceholder
    Method setPlaceholderMethod = class_getInstanceMethod(self, @selector(setPlaceholder:));
    Method setXmg_PlaceholderMethod = class_getInstanceMethod(self, @selector(setXmg_Placeholder:));
    
    method_exchangeImplementations(setPlaceholderMethod, setXmg_PlaceholderMethod);
}
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
    
    // 给成员属性赋值 runtime给系统的类添加成员属性
    // 添加成员属性
    objc_setAssociatedObject(self, @"placeholderColor", placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    // 获取占位文字label控件
    UILabel *placeholderLabel = [self valueForKey:@"placeholderLabel"];
    
    // 设置占位文字颜色
    placeholderLabel.textColor = placeholderColor;
    
}


- (UIColor *)placeholderColor
{
    return objc_getAssociatedObject(self, @"placeholderColor");
}

// 设置占位文字
// 设置占位文字颜色
- (void)setXmg_Placeholder:(NSString *)placeholder
{
    [self setXmg_Placeholder:placeholder];
    
    self.placeholderColor = self.placeholderColor;
}

使用collectionView的时候有时候会出现下面不会刚好占满的情况,这时候我们要进行补充数据

当我们点击url跳转的时候可以使用webView也可以使用手机浏览器

  1. Safari openURL :自带很多功能(进度条,刷新,前进,倒退等等功能),必须要跳出当前应用
  2. UIWebView (没有功能) ,在当前应用打开网页,并且有safari,自己实现,UIWebView不能实现进度条
  3. SFSafariViewController:专门用来展示网页 需求:即想要在当前应用展示网页,又想要safari功能 iOS9才能使用
    3.1 导入#import <SafariServices/SafariServices.h>
  4. WKWebView :iOS8 (UIWebView升级版本,添加功能 1.监听进度 2.缓存)
    4.1 导入#import <WebKit/WebKit.h>

WKWebView的使用


- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    self.webView.frame = self.containerView.bounds;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    WKWebView *webView = [[WKWebView alloc] init];
    //添加网页
    [self.containerView addSubview:webView];
    self.webView = webView;
    
    // 展示网页
    [webView loadRequest:[NSURLRequest requestWithURL:self.url]];
    
    // KVO监听属性改变
    /*
     Observer:观察者
     KeyPath:观察webView哪个属性
     options:NSKeyValueObservingOptionNew:观察新值改变
     
     KVO注意点.一定要记得移除
     */
    
    [webView addObserver:self forKeyPath:@"canGoBack" options:NSKeyValueObservingOptionNew context:nil];
    [webView addObserver:self forKeyPath:@"canGoForward" options:NSKeyValueObservingOptionNew context:nil];
    [webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
    [webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    
    
    
}
- (IBAction)goBackItemClick:(UIBarButtonItem *)sender
{
    [self.webView goBack];
}
- (IBAction)goOnItemClick:(id)sender
{
    [self.webView goForward];
}
- (IBAction)refreshItemClick:(UIBarButtonItem *)sender
{
    [self.webView reload];
}

#pragma mark - KVO观察到新值会调用 -
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    self.goOnItem.enabled = self.webView.canGoForward;
    self.goBackItem.enabled = self.webView.canGoBack;
    self.title = self.webView.title;
    self.progressView.progress = self.webView.estimatedProgress;
    self.progressView.hidden = self.webView.estimatedProgress>=1;
    
}

- (void)dealloc
{
    [self.webView removeObserver:self forKeyPath:@"canGoBack"];
    [self.webView removeObserver:self forKeyPath:@"canGoForward"];
    [self.webView removeObserver:self forKeyPath:@"title"];
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];

    
}

获取缓存的大小

  1. 使用SDWebImage自带的方法实现
  //sdWebImage自带的计算缓存大小的方法
    NSUInteger cacheNumber = [SDImageCache sharedImageCache].getSize;
    BDJLog(@"缓存大小%lu", cacheNumber);

利用NSFileManager计算文件的的大小

// NSFileManager
    // attributesOfItemAtPath:指定文件路径,就能获取文件属性
    // 把所有文件尺寸加起来
    
    // 获取Caches文件夹路径
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
    
    // 获取default文件路径
    NSString *defaultPath = [cachePath stringByAppendingPathComponent:@"default/com.hackemist.SDWebImageCache.default/0ccb23cf1c79acaa461c1a43cddc6759.png"];
    
    // 遍历文件夹所有文件,一个一个加起来
    
    // 获取文件管理者
   NSFileManager *mgr = [NSFileManager defaultManager];
    
    // 获取文件属性
    // attributesOfItemAtPath:只能获取文件尺寸,获取文件夹不对,
   NSDictionary *attr = [mgr attributesOfItemAtPath:defaultPath error:nil];
    
    // default尺寸
   NSInteger fileSize = [attr fileSize];
    
    NSLog(@"图片的大小 = %ld",fileSize);
  • 利用FileManager删除缓存
- (NSString *)getSizeString
{
    NSInteger totalSize = [self getMyFileSize:CachePath];
    NSString *str = @"清除缓存";
    if (totalSize > 1000 * 1000)
    {
        CGFloat fileSize = totalSize / 1000.0/1000.0;
        str = [NSString stringWithFormat:@"%@(%.1fMB)", str, fileSize];
    }
    else if (totalSize > 1000 )
    {
        CGFloat fileSize = totalSize / 1000.0;
        str = [NSString stringWithFormat:@"%@(%.1fKB)", str, fileSize];
    }
    else if (totalSize > 0)
    {
        CGFloat fileSize = totalSize;
        str = [NSString stringWithFormat:@"%@(%.1fdB)", str, fileSize];
    }
    
    return str;
}

//自己去实现SDWebImage的底层

-(NSInteger)getMyFileSize:(NSString *)directoryPath
{
    NSFileManager *mgr = [NSFileManager defaultManager];
    //获取文件下所有的子路径
    NSArray *subPaths = [mgr subpathsAtPath:directoryPath];
    BDJLog(@"%@", subPaths);
    //遍历他的子路径
    NSInteger totalSize = 0;
    for (NSString *subPath in subPaths)
    {
        NSString *fileCurrentPath = [directoryPath stringByAppendingPathComponent:subPath];
        //判断是否是隐藏文件
        if ([fileCurrentPath containsString:@".DS"]) continue;
        //判断是否为文件夹
        BOOL isDirectory;
        //判断文件是否存在
        BOOL isExist = [mgr fileExistsAtPath:fileCurrentPath isDirectory:&isDirectory];

        if (!isExist || isDirectory) continue;
        //获取文件的属性
        NSDictionary *attri = [mgr attributesOfItemAtPath:fileCurrentPath error:nil];
        //attributesOfItemAtPath:只能获取文件尺寸,获取文件夹不对,
        NSInteger fileSize = [attri fileSize];
        totalSize += fileSize;
    }

    BDJLog(@"%ld", totalSize);

    return totalSize;
}
- 删除操作 -

{
    NSFileManager *mgr = [NSFileManager defaultManager];
    NSArray *subPaths = [mgr subpathsAtPath:CachePath];
    
    for (NSString *subPath in subPaths)
    {
        NSString * deleteStr = [CachePath stringByAppendingPathComponent:subPath];
        [mgr removeItemAtPath:deleteStr error:nil];
    }
    [self.tableView reloadData];
}

封装文件管理业务类


+ (NSInteger)getFileSize:(NSString *)directoryPath
{
    NSFileManager *mgr = [NSFileManager defaultManager];
    
    BOOL isDirectory;
    
    BOOL isExist = [mgr fileExistsAtPath:directoryPath isDirectory:&isDirectory];
    
    if (!isExist||!isDirectory)
    {
        // 抛异常
        // name:异常名称
        // reason:报错原因
        NSException *excp = [NSException exceptionWithName:@"pathError" reason:@"经输入正确的文件的路径" userInfo:nil];
        //抛出
        [excp raise];
    }
    // NSFileManager
    // attributesOfItemAtPath:指定文件路径,就能获取文件属性
    // 把所有文件尺寸加起来
    
    NSArray *subPaths = [mgr subpathsAtPath:directoryPath];
    NSInteger totalSize = 0;

    for (NSString *subPath in subPaths)
    {
        NSString *filePath = [directoryPath stringByAppendingPathComponent:subPath];
        //判断是否为隐藏文件
        if ([filePath containsString:@".DS"]) continue;
        //判断是否为文件
        BOOL isDirectory;
        //判断文件是否存在
        BOOL isExist = [mgr fileExistsAtPath:directoryPath isDirectory:&isDirectory];
        
        if (!isExist||!isDirectory) continue;
        
        NSDictionary *fileDic = [mgr attributesOfItemAtPath:filePath error:nil];
        NSInteger fileSize = [fileDic fileSize];
        totalSize +=fileSize;
        
    }
    return totalSize;

}

+ (void)removeDirectoryPath:(NSString *)directoryPath
{
    NSFileManager *mgr = [NSFileManager defaultManager];
    //判断是否为文件夹
    BOOL isDirectory;
    
    //a判断是否存在
    BOOL isExist = [mgr fileExistsAtPath:directoryPath isDirectory:&isDirectory];
    
    if (!isExist || !isDirectory)
    {
        //抛出异常
        NSException *excp = [NSException exceptionWithName:@"path error" reason:@"请输入正确的文件路径" userInfo:nil];
        
        [excp raise];
    }
    //所有子路径
    NSArray *subPaths = [mgr subpathsAtPath:directoryPath];
    
    
    for (NSString *subPath in subPaths)
    {
        NSString *filePath = [directoryPath stringByAppendingPathComponent:subPath];
        
        [mgr removeItemAtPath:filePath error:nil];
        
        
        
    }
    
    
}

计算过程如果太多的话 会造成手机太卡,所有我们需要加入子线程


//完整实现,不能让计算文件的过程影响手机的流畅
+ (void)getFileSize:(NSString *)directoryPath completion:(void (^)(NSInteger))completion
{
   
    NSFileManager *mgr = [NSFileManager defaultManager];
    
    BOOL isDirectory;
    
    BOOL isExist = [mgr fileExistsAtPath:directoryPath isDirectory:&isDirectory];
    
    if (!isExist||!isDirectory)
    {
        // 抛异常
        // name:异常名称
        // reason:报错原因
        NSException *excp = [NSException exceptionWithName:@"pathError" reason:@"经输入正确的文件的路径" userInfo:nil];
        //抛出
        [excp raise];
    }
    // NSFileManager
    // attributesOfItemAtPath:指定文件路径,就能获取文件属性
    // 把所有文件尺寸加起来
    dispatch_async(dispatch_get_global_queue(0, 0), ^
    {
       
        
        NSArray *subPaths = [mgr subpathsAtPath:directoryPath];
        NSInteger totalSize = 0;
        
        for (NSString *subPath in subPaths)
        {
            NSString *filePath = [directoryPath stringByAppendingPathComponent:subPath];
            //判断是否为隐藏文件
            if ([filePath containsString:@".DS"]) continue;
            //判断是否为文件
            BOOL isDirectory;
            //判断文件是否存在
            BOOL isExist = [mgr fileExistsAtPath:directoryPath isDirectory:&isDirectory];
            
            if (!isExist||!isDirectory) continue;
            
            NSDictionary *fileDic = [mgr attributesOfItemAtPath:filePath error:nil];
            NSInteger fileSize = [fileDic fileSize];
            totalSize +=fileSize;
            
        }
        
        //计算完成,返回主线程
        dispatch_sync(dispatch_get_main_queue(), ^
        {
            if (completion)
            {
                completion(totalSize);
            }
        });
        
    });
    
}

按钮的状态分析

一、按钮的状态
 1.UIControlStateNormal
 1> 除开UIControlStateHighlighted、UIControlStateDisabled、UIControlStateSelected以外的其他情况,都是normal状态
 2> 这种状态下的按钮【可以】接收点击事件
 
 2.UIControlStateHighlighted
 1> 【当按住按钮不松开】或者【highlighted = YES】时就能达到这种状态
 2> 这种状态下的按钮【可以】接收点击事件
 
 3.UIControlStateDisabled
 1> 【button.enabled = NO】时就能达到这种状态
 2> 这种状态下的按钮【无法】接收点击事件
 
 4.UIControlStateSelected
 1> 【button.selected = YES】时就能达到这种状态
 2> 这种状态下的按钮【可以】接收点击事件
 
 二、让按钮无法点击的2种方法
 1> button.enabled = NO;
 *【会】进入UIControlStateDisabled状态
 
 2> button.userInteractionEnabled = NO; 
 *【不会】进入UIControlStateDisabled状态,继续保持当前状态

当我们点击已经selected的按钮的时候 还会出现高亮的效果,

去掉高亮,因为我们点击一次按钮他就会调用一次sethight方法,所以我们要重写他的setHilight方法,

下划线的宽度

//下划线的设置的第一种方法
    CGSize textSize = [firstTitleBtn.titleLabel.text sizeWithFont:firstTitleBtn.titleLabel.font];
    //下划线的设置的第二种方法
    NSMutableDictionary *attribus = [NSMutableDictionary dictionary];
    
    attribus[NSFontAttributeName] = firstTitleBtn.titleLabel.font;
    CGSize testSize = [firstTitleBtn.currentTitle sizeWithAttributes:attribus];


//第三种处理发放
underLineView.width = firstTitleBtn.titleLabel.width +10;

全屏穿透效果

通过控制tableView的contentInset属性来控制显示
在viewDidload的添那边距 由于导航栏的存在,他会帮我们自动添加64.
如果在其他地方的设置didselect。 他的那边距=64.现在设置,直接是将他的那边的改为你设置的数据40

 self.tableView.contentInset = UIEdgeInsetsMake(BDJTilteViewHight, 0, 0, 0);
    //self.automaticallyAdjustsScrollViewInsets = NO;
    self.automaticallyAdjustsScrollViewInsets = NO;

bundle 捆绑包

用来放资源的,不需要编译的 mp3 mp4 图片·

我们创建一个xib,如果我们加载的时候,我们使用的用
[NSbundle mainBundle]loadnibwithName:
因为我们的文件放到外面。他会将我们的文件 放到mainBundle里面去,storyboard等xib文件
因为我们自己的bundle文件也是在mainbundle里面,所以我们要去的自己的文件也要用mainbundle

所以 我们要先找到我们mytest.bundle要找到我们的地址
URl *myUrl = [NSbundle mainBundle] Urlfor;
[nsbundle bundleWithUrl];
我们找到bundle 经常用的是找到里面文件的全路径
imagenamed的方法 是去mainbundle里面找文件的,如果在其他地方是找不到的,所以要使用imageWithContentfile
找到文件bundle路径的方法

  // 方法1
    UIImage *image = [UIImage imageNamed:@"MyTest.bundle/Test"];

 // 方法2
    NSString *file1 = [[NSBundle mainBundle] pathForResource:@"MyTest.bundle/Test" ofType:@"png"];
    UIImage *image1 = [UIImage imageWithContentsOfFile:file1];

// 方法3
    NSString *path = [[NSBundle mainBundle] pathForResource:@"MyTest" ofType:@"bundle"];
    NSBundle *bundle = [NSBundle bundleWithPath:path];
    
    NSString *file2 = [bundle pathForResource:@"Test" ofType:@"png"];
    UIImage *image2 = [UIImage imageWithContentsOfFile:file2];

tableView的重要属性

tableView.contentSize.height = 内容的高度
tableView.contentOffsetY = frame的顶部和contensize的顶部的差值,
tableView.contentInset = 在内容周边添加的间距,始终粘着内容
tableVIew的footerView和tableVIewheaderView这些都是内容,添加了之后,会增加内容的高度。
添加的子控件,不会增加内容的size。

ITableView *tableView = [[UITableView alloc] init];
    tableView.backgroundColor = [UIColor orangeColor];
    tableView.delegate = self;
    tableView.dataSource = self;
    tableView.frame = CGRectMake(50, 100, 200, 300);
    [self.view addSubview:tableView];

    
    //内边距
   // tableView.contentInset = UIEdgeInsetsMake(64, 0, 49, 0);
    //headerVIew
    UIView *headerView = [[UIView alloc] init];
    headerView.frame = CGRectMake(0, 0, tableView.frame.size.width, 64);
    headerView.backgroundColor = [UIColor yellowColor];
    tableView.tableHeaderView = headerView;//contentSize 944
    
    //footView
    UIView *footerView = [[UIView alloc] init];
    footerView.frame = CGRectMake(0, 0, tableView.frame.size.width, 64);
    footerView.backgroundColor = [UIColor redColor];
    tableView.tableFooterView = footerView;//contentSize 1008
    
    //添加额外的子l控件
    UIView *header2View = [[UIView alloc] init];
    header2View.frame = CGRectMake(0, -64, tableView.frame.size.width, 64);
    header2View.backgroundColor = [UIColor redColor];
    [tableView addSubview:header2View ];//contentSize 1008

懒加载子控制器的View

方法一,传递参数,知道添加第几个控制器

//懒加载子控制器的View
- (void)addChildViewInScrollView:(NSInteger)index
{
    UIViewController *currentVC = self.childViewControllers[index];
    
    //如果Viewi已经被加载过
    if (currentVC.isViewLoaded) return;
    
    //取出VIew
    UIView *childView = currentVC.view;
    
    //设置子控制器View的gframe
    childView.frame = CGRectMake(self.mainScrollView.width * index, 0, self.mainScrollView.width, self.mainScrollView.height);
    [self.mainScrollView addSubview:childView];
}

第二种方式


CGFloat scrollViewW = self.mainScrollView.width;
    NSInteger index = self.mainScrollView.contentOffset.x / scrollViewW;
    
    UIViewController *currentVC = self.childViewControllers[index];
    
    //如果Viewi已经被加载过 判断方法还可以有view的superView是否有值
    //if (currentVC.isViewLoaded) return;
    
    //取出VIew
    UIView *childView = currentVC.view;
    
    //设置子控制器View的gframe
    childView.frame = self.mainScrollView.bounds;

这种设置方式 注意设置scrollView偏移量的时候要使用
elf.mainScrollView.contentOffset = CGPointMake(offSetX, self.mainScrollView.contentOffset.y);

监听状态栏和tabBar按钮的点击

当当前视图中的scrollView有个且 scrollstotop都是YES的时候这个属性是无法执行的,因此,我们要把除了当前要懂得视图之外的其他的视图改成NO;

//监听tabBar的点击
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(nonnull UIViewController *)viewController
//{
//    BDJLog(@"tabBar点击了");
}

//监听状态栏的点击
//- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
//{
//    if ([touches.anyObject locationInView:nil].y <= 20)
//    {
//        BDJLog(@"点击了状态栏");
//    }
//}

自定义上拉加载和下拉刷新控件

图片处理一些操作


// 在周边加一个边框为1的透明像素

- (UIImage *)imageAntialias
{
    CGFloat border = 1.0f;
    
    CGRect rect = CGRectMake(border, border, self.size.width - 2 *border, self.size.height - 2 * border);
    UIImage *img = nil;
    
    UIGraphicsBeginImageContext(rect.size);
    
    [self drawInRect:CGRectMake(-1, -1, self.size.width, self.size.height)];
    img = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    UIGraphicsBeginImageContext(self.size);
    [img drawInRect:rect];
    UIImage *antiImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return antiImage;;
}


- (UIImage *)circleImage
{
    //开启图片上下文
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0);
    
    //描绘裁剪区域
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
    //裁剪
    [path addClip];
    //画图片
    [self drawAtPoint:CGPointZero];
    //5. 取出图片
    UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return circleImage;
    
}

+(UIImage *)circleImageWithName:(NSString *)name
{
    return [[self imageNamed:name] circleImage];
    
}

计算某个Label的Size,内容确定,高度变化


BDJTopic *topic = self.topics[indexPath.row];
    
    CGFloat cellHight = 0;
    
    cellHight += 55;
    CGSize textMaxSize = CGSizeMake(kSCREEN_WIDTH - BDJMargin * 2, MAXFLOAT);
    
    cellHight += [topic.text sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize:textMaxSize].height + BDJMargin;
    
    CGSize newCellSize = [topic.text boundingRectWithSize:textMaxSize options:nil attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil].size;
    
    //工具跳的高度
    cellHight += 35 + BDJMargin;
    
    // 这2个方法只适合计算单行文字的宽高
    //    [topic.text sizeWithFont:[UIFont systemFontOfSize:15]].width;
    //    [UIFont systemFontOfSize:15].lineHeight;

估算cell的高度

    self.tableView.estimatedRowHeight = 100;

由于tableView的heightForRow方法的调用频率太高,所以要提前估算cell的高度,这样系统就会根据估算的cell高度来创建一开始的的cell。苹果的一次性计算,是因为滚动条要提前根据内容的高度,计算出出自己的长度。这个计算不是特别的准确,如果设置了估算高度之后,他会根据大概有多少个cell,然后计算cellforrow方法,

预设高度与实质高度差别太大的话,会是滚动条闪烁,IOS7,之后才可以使用,
优点,降低heifhtForRow方法调用,延迟执行计算滚动条的高度。
缺点:滚动条长度不确定,不稳定,甚至卡顿

用xib创建的View

xib 起名字的时候,要注意更控制器的额名字不要相似

有时候我们创建的View看不见,如果我们打印出来的,他的frame有值,但是等一会打印,他的frame就没有值,默认丛xib加载的View的autoresizingMask = YES,autoresizing默认会跟着父控制器的伸缩,
一般来说1.xib加载的View会是YES ;2.控制器的View
假设我们的cell 刚开始 size = 320 170;创建的中间的xibView 的size = 240 80;如果dangcell的frame发生改变的时候,370 85;这是xib创建的View也会相应地发生改变。变成240+ 50, 80-85 <0;就会变成290,0;所以就会发生我们看不到的情况

cell的显示顺讯,先调用,个数,-> 每一行的高度->contensize - >

处理label现实的数字

//设置播放数
    if (topic.playcount > 10000)
    {
        self.playCountLabel.text = [NSString stringWithFormat:@"%.1f播放", topic.playcount/ 10000.0];
    }
    else
    {
      self.playCountLabel.text = [NSString stringWithFormat:@"%ld播放", topic.playcount];
    }
    
    
    //播放时间
    
    self.playTimeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld", topic.voicetime / 60, topic.voicetime % 60];
   

使用AFNetWork监听网络

注意:要手动开始监听方法

//开始监听网络
 [[AFNetworkReachabilityManager sharedManager] startMonitoring];

根据不同的网络情况,做一些操作

//根据网络状态来判断加载图片
    AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
    
    BDJLog(@"是否可用%d", mgr.isReachable);
    //获得原图,SDWebImage是根据url作为key
    UIImage *origalImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:@"imageUrl"];
    if (origalImage) //图片已经被下载过了
    {
        self.topicVoiceImageView.image = origalImage;
    }
    else //下载图片
    {
        
       
        
        if (mgr.isReachableViaWiFi) //WIFI网络 ,下载原图
        {
            BDJLog(@"wifi下载");
         
        }
        else if (mgr.isReachableViaWWAN)
        {
            NSLog(@"3G/4G下载");
#warning downloadOriginImageWhen3GOr4G配置项的值需要从沙盒里面获取
            //3G/4G网络下需要下载原图
            BOOL downloadOriginImageWhen3GOr4G = YES;
            if (downloadOriginImageWhen3GOr4G)
            {
            
            }
            else
            {
                
            }

        }
        else //没有网络的情况下
        {
            BDJLog(@"没有网络");
        }
        
    }

当使用SDWebImage的时候,要注意稳定内存

只清空内存缓存,沙盒不清

    [[SDImageCache sharedImageCache]clearMemory ];

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • 1.设置启动图的作用 在没设置应用启动图的情况下,应用启动时的前一两秒会显示白屏,影响用户体验 2.设置启动图的步...
    happycolt阅读 1,695评论 0 1
  • 两种方法设置: LaunchScreen.storyboard在LaunchScreen.storyboard中拖...
    KnowWhy阅读 354评论 0 0
  • AppIcon图标设置 1.(推荐)这款软件 2.AppIcon图标需要一张1024x1024的图片,然后按照下面...
    CoderLGL阅读 2,291评论 0 1
  • 两种方法设置: LaunchScreen.storyboard 在LaunchScreen.storyboard中...
    阿兹尔阅读 1,174评论 0 0
  • 践行写作打卡日更第6天 二月的时光在匆忙和琐碎中即将结束,孩子寒假也快结束了,为了给孩子收收心,决定今天带孩子去新...
    美韵森阅读 308评论 0 6