iOS开发--项目拾疑_杂碎的知识点(1)

有段时间没写东西了,最近都是机械搭项目。趁着后台,出接口的这几天。
咱也定一个小目标,比如说-----
算了,不吹牛逼了,怕被打死。
最近刚做一个项目,准备在项目中穿插着写一点东西吧。

1杂碎的知识点
2讲一下项目大体的架构,分析一下项目用的三方的一些问题和选择
3讲一下,我这个菜鸡对项目网络层以及数据存储层的设计以及分析

项目没做完之前,我会不断更新杂碎的知识点这篇,等项目over.和你们好好唠唠项目整体。
好了不Xx了

1.1 UINavigationController

导航栏控制器基本是项目必备啊,所以我们UI大姐们也是想着花样搞这个东西。我们做这方面开发的都是到NVC(码字 有点烦,后面都这样简称了),基本构造做开发的都是知道,是一个容器类 下面的VCs都是放在 stack中的。所以说,在stack里面那么多VC都是公用一个navigationBar啊。UI大姐就喜欢一个VC 拥有一个不同的bar....欲哭无泪。
现在按按修改程度,一点一点写。

1.1.1bar 上的返回按钮太丑了 换掉0.0
~~~~~第二个方法就是整个替换掉leftItem,当然随之而来的问题就是要实现点击返回功能和左滑返回功能。
因为要实现左滑 最好还是重写一个NVC子类 而不是用appearce
```
//遵循手势的协议
@interface IGONavigationController ()<UIGestureRecognizerDelegate>

- (void)viewDidLoad{
    [super viewDidLoad];
    self.interactivePopGestureRecognizer.delegate = self;
}
//替换掉各个页面的返回按钮
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{
    //设置返回按钮
    viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"fanhui"] style:UIBarButtonItemStyleDone target:self action:@selector(popViewControllerAnimated:)];
    [super pushViewController:viewController animated:animated];
}
//右滑返回的处理
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    BOOL ok = YES; // 默认为支持右滑反回
    if ([self.topViewController isKindOfClass:[RootViewController class]] ||
        [self.topViewController isKindOfClass:[Root1ViewController class]] ||
        [self.topViewController isKindOfClass:[Root2ViewController class]] ||
        [self.topViewController isKindOfClass:[Root3ViewController class]]) {
        return NO;
    }
    return ok;
}
```
要注意的是 开起左滑 返回 移动去去掉 NVC 的rootVC 不然就会出现空stack的问题,从而导致各种问题。
######1.1.2bar  有的页面需要,有的页面不需要
这个也是挺烦的,我看到很多同鞋。在处理这个问题上,都会这么写。加入A页面需要,B页面不需要的话
```
A
- (void)viewWillAppear:(BOOL)animated {
    self.navigationController.navigationBar.hidden = NO;
}
B
- (void)viewWillAppear:(BOOL)animated {
    self.navigationController.navigationBar.hidden = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
    self.navigationController.navigationBar.hidden = YES;
}
```
这种做法,也就效果勉强出来了,不过会带来一系列的问题
·····1 左滑 返回的时候NVC 无法分清那个VC 有Bar .出现显示问题
·····2当2个VC对应 statusBar 的字体颜色不一样的时候。上面这种做法,虽然隐藏了Bar 但在VC中重写`preferredStatusBarStyle`依旧没有作用的。NVC很难分清其中的界限。
正确的做法应该是
这种修改Bar 的工作还得交给代理去做,毕竟出现的意外情况,苹果的大牛们都考虑到了,代码要写在改写的地方。
因为我子类化得NVC用的地方很多,所以对于Bar的代理 我基本会放在rootVC中
下面的代码 就是在 SearchViewController和SearchResultController中隐藏了Bar
在ProductDetailViewController中对Bar的样式 进行了修改。
```
//在rootVC 中 遵循NVC代理 UINavigationControllerDelegate
//隐藏导航栏
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    // 隐藏Bar
    BOOL isShowHomePage = [viewController isKindOfClass:[SearchViewController class]] || [viewController isKindOfClass:[SearchResultController class]];
    [self.navigationController setNavigationBarHidden:isShowHomePage animated:YES];
    UIImage *shadowImage = self.navigationController.navigationBar.shadowImage;
    UINavigationBar *bar = self.navigationController.navigationBar;

    if ([viewController isKindOfClass:[ProductDetailViewController class]]) {
        bar.shadowImage = [UIImage new];
        [bar lt_setBackgroundColor:[UIColor clearColor]];
    }else {
        bar.shadowImage = shadowImage;
        [bar setBackgroundImage:[UIImage imageNamed:@"导航栏"] forBarMetrics:UIBarMetricsDefault];
    }
}
```
这样 在左滑的时候消除了显示问题,以及在在隐藏了Bar的VC中无法控制statusBar的状态颜色问题。
######1.1.3 每个bar完全不同
童鞋 全隐藏 自定义吧QAQ
#1.2UINavigationBar
大家现在都是最低支持7以上了,太老的东西就不涉及了。
bar 有2个烦人的地方就是偏移量和透明度了
######1.2.1偏移量
我们知道默认`translucent = YES`。就是Bar 是有透明度的。
在有透明度的情况下,系统默认`automaticallyAdjustsScrollViewInsets`属性是YES就是对于scrollerview的子类会默认content偏移64个单位。这样做的目的,既然Bar都是透明的了,系统就觉得你的scrollerView一定在会在(0,0)点,content偏移一个64个单位。在你滑动的时候,隐藏在Bar下面的Content会有一个模糊显示的效果。QAQ
如果你不想要这个偏移量
1 设置translucent = NO,既然Bar不透明。自然不需要偏移量喽
2 关闭这个偏移量,automaticallyAdjustsScrollViewInsets = NO
提一下像tableView,在storyboard 设置上下左右的约束。结果cell上面多了一块空白。就是这个问题。  
######1.2.2透明度
这种需求现在太多了,尤其都要做成淘宝那样的详情页,烦的一腿。现在我就在分析一下。
首先如果想滑动控制Bar的透明度,translucent 属性一定要设置成YES(默认)
当Bar 被设置成透明状态的时候
![ED5A2936-7199-47B4-9E14-73E44F49BE74.png](http://upload-images.jianshu.io/upload_images/1106106-6e082fa875411d82.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
还是这张图 _UIBackdropView 这个view是设置半透明毛玻璃效果的view(当然只在透明属性为YES 或者 没有背景图片的时候才会出现)
首先我们要去掉层特殊的视觉图层 利用设置BarBackground图片
```
- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;
```
千万不要用translucent = NO 这种方法来去掉视觉图层,都设置不透明了,那我们还玩按什么是吧。。。
这里注意的是我们设置的barTintColor 以及 background 都是对_UINavigationBarground这个Imageview来进行操作的。
这时候 我们就剩下Bar 和 BarBackground两层了
首先我们来说下Bar上面设置颜色的3个方法
```
//背景颜色 继承父类的 不过这个是设置bar 的背景颜色 
@property(nullable, nonatomic,copy)   UIColor   *backgroundColor UI_APPEARANCE_SELECTOR; // default is nil. Can be useful with the appearance proxy on custom UIView subclasses.
//这个是设置bar 上面的那层 barBackground imaeView的颜色
@property(nullable, nonatomic,strong) UIColor *barTintColor NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;  // default is nil
//这个是item的颜色
@property(null_resettable, nonatomic,strong) UIColor *tintColor;

```
再来看下各个控件的高度 bar 本身是44 而barBackgoundImageView 确实64.。
这就是 为什么你设置了bar你颜色 或者 背景图片 。为什么status Bar 的背景也会跟着改变哦。
其实Bar 本身的颜色几乎很少设置,因为现在都要2个bar 一致才符合主流嘛

怎么改变barBackgroundImageView的背景颜色,又成了一个问题。因为刚才为了去掉视觉图层,我们给barBackgroundImageView 赋值了一个空图片。问题出来了,有了图片属性之后,给barBackgroundImageView设置背景颜色就没有用了,现在主流的做法是
查一个view进去  去调节这个 view的颜色 来控制bar 的背景颜色控制
写个类目 给 bar 加一个 - (void)iGo_setBackgroundColor:(UIColor *)backgroundColor
```
- (UIView *)backView
{
    return objc_getAssociatedObject(self, &backView);
}

- (void)backView:(UIView *)backView
{
    objc_setAssociatedObject(self, &backView, backView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)iGo_setBackgroundColor:(UIColor *)backgroundColor
{
    if (!self.backView) {
        [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
        self.backView = [[UIView alloc] initWithFrame:CGRectMake(0, -20, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + 20)];    
        [self insertSubview:self.backView atIndex:0];
    }
    self.backView.backgroundColor = backgroundColor;
}
```

最后 我们需要调节透明度的页面
在滑动过程中 调节颜色的透明度 就OK拉
```
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    UIColor * color = [UIColor colorWithHexString:@"#fa2245"];
    CGFloat offsetY = scrollView.contentOffset.y;
    if (offsetY > 50) {
        CGFloat alpha = MIN(1, 1 - ((50 + 64 - offsetY) / 64));
        [self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:alpha]];
    } else {
        [self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:0]];
    }
}
```

#2旋转处理
一半我我们的app不支持旋转的话 就会关掉下面这两个向选项

![](http://upload-images.jianshu.io/upload_images/1106106-fdd231479a44cc5c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
来禁止横屏。
但如果我们的app部分页面支持横屏,部分不支持的话就要做一些处理了
我们不需要对每一个VC都进行处理,只要对最外层的容器类VC重写一些方法。
例如我的所有VC都是由tabbar管理的
我会在tabbar的子类中
```
#pragma mark -- Orientation
//如果目前是竖屏 则不支持旋转,如果现在是横屏 则支持旋转
- (BOOL)shouldAutorotate{

    return !([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait);

}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return UIInterfaceOrientationPortrait;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
```

在某些需要旋转的VC继续重写这几个方法
```
//因为是个别页面是横屏 其他页面都是竖屏,这里可以直接返回YES 
//如果有特殊情况 也可以判断返回
#pragma mark -- orientation
- (BOOL)shouldAutorotate {
    return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskLandscapeRight;
}
```

这样即使是横屏状态打开app 也会自动切换成竖屏。不过如果你在tabbar 在加一些东西的话可能会出现问题。
举个例子





![2362FE5F-DDC4-48EA-951B-FBA57DB00A43.png](http://upload-images.jianshu.io/upload_images/1106106-9b578dcea13190d7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
中间这个 取 的按钮 ,按照系统的是无法实现的。又不想重新自定义tabbar。这时候我就在tabbar中中间加上一个Button.来模拟tabbar item 的功能。
这时候 从横屏 进来之后,就会出现问题,因为bar 上是无法添加约束的,所以只能用frame 布局。 但是横竖屏的宽高大小 是相反的0.0
这时候就需要判断了
```
//可以用宽高大小判断 也可以用上面的设备方向判断
CGFloat width = kScreenHeight>kScreenWidth? kScreenWidth: kScreenHeight;
    UIButton *getGoodsButton = [[UIButton alloc] initWithFrame:CGRectMake(width/2 - kButtonWidth/2, 0, kButtonWidth, kButtonHeight)];
```

这只是一盒小例子,总之 处理屏幕旋转的时候要注意布局。尤其是没有约束控制的布局
#3扫描
3.1淘宝的扫描效果(盗的图QAQ)
![2BA14FEB-7E6F-499E-827A-9FC2E02E5B61.png](http://upload-images.jianshu.io/upload_images/1106106-13b2f05677f71aec.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

这个看起来很炫酷,其实就是一个网格的图片上下移动,把多余的部分Mask 掉就可以了。
```
//放个可视面积差不多大小的view,将imageview 加上去
UIView *tempView = [[UIView alloc] initWithFrame:VISIBLERECT];
//重点
    tempView.layer.masksToBounds = YES;
    [self.view addSubview:tempView];
    _scanningImageView = [[UIImageView alloc] init];
    [tempView addSubview:_scanningImageView];
    _scanningImageView.image = [UIImage imageNamed:@"扫描网格"];
```
上下的移动的代码就不贴,思路知道了。做起来很简单
######3.2 unsupported type found
在设置`AVCaptureMetadataOutput ` 的`metadataObjectTypes`时候,一定要注意设置在载入session 之后不然就会出现 特别迷惑人的错误

![E9F4D45F-0FA8-426D-AA5C-11A7FEB11253.png](http://upload-images.jianshu.io/upload_images/1106106-837757e6464675aa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我纳闷了好久 啊 。。。。。要记得 前后 顺序 
```
[_session addInput:_input];
    [_session addOutput:_output];
    _output.metadataObjectTypes = @[AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code];
```
######3.3 坐标转换
我们知道扫描的可视范围rectOfInterest坐标系统 和 我们 UIKit用的坐标系统不一样,我们在设置这个坐标的时候有两种做法
1,根据 两种坐标系 自己换算去 其实就是将屏幕左翻转 (x,y轴对调)
CGRectMake(y的起点/屏幕的高,x的起点/屏幕的宽,扫描的区域的高/屏幕的高,扫描的区域的宽/屏幕的宽) 
2,通过系统的方法换算
在通过系统的方法换算的时候,出现了小问题
```
- (CGRect)metadataOutputRectOfInterestForRect:(CGRect)rectInLayerCoordinates NS_AVAILABLE_IOS(7_0);
```
在使用这个方法换算的时候始终是没有作用的,
其实方法是没错,但是调用的时机很重要
当我们收到`AVCaptureInputPortFormatDescriptionDidChangeNotification`通知的时候在进行左边转换就没有问题了
具体原因,我也没有找到。希望大神指点
```
[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureInputPortFormatDescriptionDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification * _Nonnull note) {
        _output.rectOfInterest = [_scanView metadataOutputRectOfInterestForRect:VISIBLERECT];
    }];
```
 #4UIButton
我们都知道button中有2个子控件 一个imageView 一个label。默认imageview 在左label 在右。我们控制好这几个控件 能满足好多需求
首先 button 是UIControl的子类
UIControl有控制content位置的属性
```
typedef NS_ENUM(NSInteger, UIControlContentVerticalAlignment) {
    UIControlContentVerticalAlignmentCenter  = 0,
    UIControlContentVerticalAlignmentTop     = 1,
    UIControlContentVerticalAlignmentBottom  = 2,
    UIControlContentVerticalAlignmentFill    = 3,
};

typedef NS_ENUM(NSInteger, UIControlContentHorizontalAlignment) {
    UIControlContentHorizontalAlignmentCenter = 0,
    UIControlContentHorizontalAlignmentLeft   = 1,
    UIControlContentHorizontalAlignmentRight  = 2,
    UIControlContentHorizontalAlignmentFill   = 3,
};
@property(nonatomic) UIControlContentVerticalAlignment contentVerticalAlignment;     // how to position content vertically inside control. default is center
@property(nonatomic) UIControlContentHorizontalAlignment contentHorizontalAlignment; // how to position content hozontally inside control. default is center
```
只要我们合理的运用 content(imageview 和 label) 可以在button 内部的16个位置上。
但有时这个东西满足不了我们的需求
看个例子

![FE0CDCAA-451F-4ACF-97BA-74694BA7548B.png](http://upload-images.jianshu.io/upload_images/1106106-d9752444e829622c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这种图片在右边 文字在左边,就令我们很蛋疼。看到这个需求有的童鞋可能就会自定义一个视图类了,其实不需要button的属性就可以帮助我们解决
```
@property(nonatomic)          UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR; // default is UIEdgeInsetsZero
@property(nonatomic)          UIEdgeInsets titleEdgeInsets;                // default is UIEdgeInsetsZero
```
可以设置图片文字的偏移量,不过此处有坑
```
#import "UIButton+Common.h"

@implementation UIButton (Common)

- (void)reverseImageAndTitle {
    CGRect imageFrame = self.imageView.frame;
    CGRect titleFrame = self.titleLabel.frame;
    self.titleEdgeInsets = UIEdgeInsetsMake(0, -imageFrame.size.width *2, 0,0 );
    self.imageEdgeInsets = UIEdgeInsetsMake(0,0, 0, -titleFrame.size.width*2);

}
@end
```
这边单位是px 不是pt 整个人都蒙了有木有。
不过还好发现了 

#5UITextField

![C04C5E25-F123-4372-A707-B14ACD5D7EAD.png](http://upload-images.jianshu.io/upload_images/1106106-2beb7f5591482bab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

设置左边图片 sb 上面没有对应的属性。。。庆幸的在textfield中还是有对应的属性 不过切图的时候记得要来拿左边的空白一起切下来

```
@property(nullable, nonatomic,strong) UIView    *leftView;        // e.g. magnifying glass
@property(nonatomic)  UITextFieldViewMode  leftViewMode;    // sets when the left view shows up. default is UITextFieldViewModeNever
```
#6.tableView collectionView
######1.圆角 始终是个争论的话题了。
各种花式的解决办法。
其实我认为,如果固定的页面 如果只有个别原角,无需优化
如果想tableview 这样大量重复的圆角,其实只要做设置一次缓存即可。开启光栅化,可解决性能问题。
什么 离屏渲染 CPU GPU线程切换消耗大量性能,我只做一次还不行meQAQ
```
//rasterize
    cell.layer.shouldRasterize = YES;
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
```
不要各种贝塞尔 各种mask 简单点好。
######2.对于selected
tableview 和 collectionview 都是支持单选的,只要重写  selected方法就行,系统在你创建cell类的时候也预留了这个方法。
不过要选择默认的selected 设置cell.seleted 是不行的
```
//collectionView
- (void)selectItemAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition;
```
seleted 可以完美的实现默认选中 单选的效果。
对于对选 智能自定义了
######3section 展开
只要用数组记录每个section 需要展示的cell 的数量 刷新view 就可以了

#7VC设置背景图片
没有必要再放在一个imageview上面 直接在VC的view.layer上画就可以了
```
 self.view.layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"beijing"].CGImage)
```










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

推荐阅读更多精彩内容