UICollectionView入门篇

1. 设计数据源和代理

每个集合视图都必须具有数据源对象。该数据源对象是内容,你的应用程序显示。它可以是应用程序数据模型中的对象,也可以是管理集合视图的视图控制器。数据源的唯一要求是它必须能够提供集合视图所需的信息,例如有多少项以及在显示这些项时要使用的视图。

UICollectionViewDelegate是一个可选的(但建议)对象管理有关的介绍,并与您的内容互动方面。虽然代表的主要工作是管理单元格突出显示和选择,但可以扩展它以提供其他信息。例如,流布局扩展了基本委托行为以自定义布局指标,例如单元格的大小和它们之间的间距

For example:

 self.collectionView.delegate = self;
 self.collectionView.dataSource = self;

2. 注册 cells 和 suppelementary Views

  • 配置cell
    • registerClass:forCellWithReuseIdentifier:
    • registerNib:forCellWithReuseIdentifier:
  • 配置suppelementary Views

    • registerClass:forSupplementaryViewOfKind:withReuseIdentifier:
    • registerNib:forSupplementaryViewOfKind:withReuseIdentifier:

For example:

 [self.collectionView registerNib:[UINib nibWithNibName:@"MyCustomCell" bundle:nil] forCellWithReuseIdentifier:@"cell"];

3. 数据源管理您的内容

  • 集合视图包含多少个部分?
  • 对于给定的部分,部分包含多少项?
  • 对于给定的部分或项目,应使用哪些视图来显示相应的内容?

For example:

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView {
        // _data is a class member variable that contains one array per section.
        return [_data count];
    }
    
-(NSInteger)collectionView:(UICollectionView*)collectionView numberOfItemsInSection:(NSInteger)section {
        NSArray* sectionArray = [_data objectAtIndex:section];
        return [sectionArray count];
    }
    
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    MyCustomCell * newCell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"cell"
                              forIndexPath:indexPath];
    
   newCell.cellLabel.text = [NSString stringWithFormat:@“Section:%d,Item:%d”,indexPath.section,indexPath.item];
    return newCell;
}
    

4. 设计数据对象

高效的数据源使用节和项来帮助组织其底层数据对象。将数据组织成部分和项目可以使以后更轻松地实现数据源方法。而且由于您经常调用数据源方法,因此您需要确保这些方法的实现能够尽快检索数据。

比如下面这个结构

5. 插入,删除和移动部分和项目

在通知集合视图任何更改之前更新数据源至关重要,要插入,删除或移动单个部分或项目,请按照下列步骤操作:

  • 更新数据源对象中的数据
  • 调用集合视图的相应方法以插入或删除节或项。

以编程方式添加,删除或移动单个项目时,集合视图的方法会自动创建动画以反映更改。但是,如果要同时为多个更改设置动画,则必须在块内执行所有插入,删除或移动调用,并将该块传递给该performBatchUpdates:completion:方法。然后,批量更新过程会同时为所有更改设置动画,您可以自由地混合调用以插入,删除或移动同一块中的项目。

For example:

[self.collectionView performBatchUpdates:^{
   NSArray* itemPaths = [self.collectionView indexPathsForSelectedItems];
 
   // Delete the items from the data source.
   [self deleteItemsFromDataSourceAtIndexPaths:itemPaths];
 
   // Now delete the items from the collection view.
   [self.collectionView deleteItemsAtIndexPaths:itemPaths];
} completion:nil];

6. 管理选择和亮点的可视状态

backgroundView当单元格第一次加载以及单元格未突出显示或未选中时,单元格的属性将始终为默认视图。selectedBackgroundView每当突出显示或选择单元格时,该属性都会替换默认的背景视图。在这种情况下,当选择或突出显示时,单元格的背景颜色将从红色变为白色。

For example:

#import "MyCustomCell.h"
    
@implementation MyCustomCell
    
- (void)awakeFromNib {
    [super awakeFromNib];
    
    UIView * backgroundView = [[UIView alloc] initWithFrame:self.bounds];
    backgroundView.backgroundColor = [UIColor redColor];
    self.backgroundView = backgroundView;
    
    UIView * selectedBGView = [[UIView alloc] initWithFrame:self.bounds];
    selectedBGView.backgroundColor = [UIColor whiteColor];
    self.selectedBackgroundView = selectedBGView;
    // Initialization code
}
    
@end

7. 显示单元格的编辑菜单

屏幕快照 2018-12-18 下午6.05.55

  • 委托必须实现与处理操作相关的所有三种方法:
    • collectionView:shouldShowMenuForItemAtIndexPath:
    • collectionView:canPerformAction:forItemAtIndexPath:withSender:
    • collectionView:performAction:forItemAtIndexPath:withSender:

collectionView:shouldShowMenuForItemAtIndexPath:方法必须返回YES。
collectionView:canPerformAction:forItemAtIndexPath:withSender:方法必须返回YES至少一个所需的动作。集合视图支持以下操作:
cut:copy:paste:

For example:

-(BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath{
    
    return YES;
}
    
- (BOOL)collectionView:(UICollectionView *)collectionView
      canPerformAction:(SEL)action
    forItemAtIndexPath:(NSIndexPath *)indexPath
            withSender:(id)sender {
    // Support only copying and pasting of cells.
    if ([NSStringFromSelector(action) isEqualToString:@"copy:"]
        || [NSStringFromSelector(action) isEqualToString:@"paste:"])
        return YES;
    
    // Prevent all other actions.
    return NO;
}
-(void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender{
    
    if ([NSStringFromSelector(action) isEqualToString:@"copy:"]){
        if(_selectCopyArray.count) [_selectCopyArray removeAllObjects];
        [_selectCopyArray addObject:@[@"1",@"2"]];
    }
    
    if ([NSStringFromSelector(action) isEqualToString:@"paste:"]){
        
        [self.dataSource addObjectsFromArray:_selectCopyArray];
        [self.collectionView reloadData];
    
    }
        
    
    
    
}

8. 流式布局UICollectionViewFlowLayout

  • 描述

    您可以使用具体的布局对象(UICollectionViewFlowLayout类)在集合视图中排列项目。流布局实现了基于行的分解布局,这意味着布局对象将单元放置在线性路径上,并尽可能多地沿着该行拟合单元。当布局对象在当前行上没有空间时,它会创建一个新行并在那里继续布局过程

    可以通过编程方式或使用Xcode中的Interface Builder来配置流布局。配置流布局的步骤如下:

    • 创建流布局对象并将其分配给集合视图
    • 配置单元格的宽度和高度。
    • 为线条和项目设置间距选项(根据需要)。
    • 如果需要节标题或节页脚,请指定其大小。
    • 设置布局的滚动方向。

自定义流布局属性

  • ①指定流布局中的项目大小

    • xib 实现

      • 滚动方向

      屏幕快照 2018-12-19 上午10.06.44

      • 大小间距等属性设置

      屏幕快照 2018-12-19 上午10.06.30

    注意:您必须至少指定单元格的宽度和高度,如果不这样做,则会为您的项目指定宽度和高度为0,并且永远不会显示。

    • 代码实现

      • 单元格相同的大小直接设置self.flowLayout.itemSize

      • 单元格指定不同的大小实现
        collectionView:layout:sizeForItemAtIndexPath:。可以使用提供的索引路径信息来返回相应项的大小。


        如果要动态改变项目的间距或大小,可以使用UICollectionViewDelegateFlowLayout 协议的方法。

        //UICollectionViewDelegateFlowLayout 代理方法
        - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
        - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;
        - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;
        - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;
        - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;
        - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;

        如果存在给定方法,则流布局对象将调用该方法,而不是使用它具有的固定值。
        实现必须为集合视图中的所有项返回适当的值。

        注意:为单元格指定不同的大小时,单行上的项目数可能因行而异。

  • ②指定项目和行之间的空间

    使用流布局,您可以指定同一行上的项目之间的最小间距以及连续行之间的最小间距。提供的间距仅为最小间距。由于它如何布置内容,流布局对象可能会将项之间的间距增加到大于您指定的值的值。当布置的项目具有不同的尺寸时,布局对象可以类似地增加实际的行间距。

    • 项目之间的实际间距可能大于最小值

    • 如果项目大小不同,行间距会有所不同

      • xib 实现见上面的图
      • 代码实现
        • 固定间距 self.flowLayout.minimumLineSpacing和 self.flowLayout.minimumInteritemSpacing属性静态设置间距
        • collectionView:layout:minimumLineSpacingForSectionAtIndex:和collectionView:layout:minimumInteritemSpacingForSectionAtIndex:方法。
  • ③使用Section Insets来调整内容的边距

    使用insets在节的标题视图之后和页脚视图之前插入空格或者使用insets在内容的两侧插入空


    格。

    部分插入更改了布置单元格的可用空间,可以限制给定行中单元格的数量。

总结

这篇文章包含了一个初学者刚开始接触UICollecctionView 所需要了解的内容,也一步步教你怎么使用一个最基础的视图。包含代理方法,itemSize,itemInset sectionInset 等等。
基本上这些已经能满足一个初学者的要求了,如果需要进阶教程,后续会有进阶教程。

2018/8/8 posted in  iOS

Apple Developer Team

已经被添加到开发组当中,但是却一直在Xcode->Preferences->accounts 找不到自己已经添加的开发组。
xcode_Account

在百度搜了很久一直没有找到解决问题的答案,于是去了Google搜索,在stackoverflow发现了解决问题的答案。

链接在此 Development team not showing in Xcode

问题分析

首先博主声明苹果有两个系统

  • Developer.apple.com system
  • App Store connect system

这是两个不同的系统,必须要保证同时加入了两个系统中的Team,如果对方要加入一个成员到开发组,从Developer开发者中心添加。

看到这里依然没有解决我的答案,而且苹果已经在2018年修复了上面的问题。

往下我看到了一个很重要的答案,就是权限问题,如果有足够的权限在开发者中心看到的页面如下。

如果没有足够的权限红色部分是不存在的,所以在xcode中无法查看自己所在的team,也是是无法管理描述文件,证书等等的,所以如果你没有看到红框部分,那么就需要找到管理员加入相应的权限。

答案:

管理员去到AppStoreConnect,点击人员,划到最底下的 Developer Resources 勾选。

这个就代表你就可以访问证书,标识,描述文件了,去到开发者中心也就发现了变化。

此时重新打开Xcode->Preferences->accounts会发现自己加入的开发组已经出现。

总结:

当你邀请某个开发人员加入开发组的时候一定要勾选允许资源访问,要不然也会遇到和我一样的问题。

还有就是已经添加过了,但是没有足够的权限,就像我上面说的去AppStoreConnect修改权限。

2018/8/6 posted in  iOS

sizeThatFits和sizeToFit

今天帮同事看一个布局约束的问题,(代码也是从别人手中接过来的,所以并不清楚怎么布局的)
view是用xib画的,约束设置很多,本以为是约束的问题,设置了约束还是不能更改整个view的高度。

最后找了一会,我发现了一个方法 sizeThatFit 在sizeThatFit内部返回了size,所以刚才尽管指定的约束改了,但是还是不影响下面的方法返回size。

所以就写了这个东西给不了解的同学一点点经验。

- (void)sizeToFit;                       // calls sizeThatFits: with current view bounds and changes bounds size.
- (CGSize)sizeThatFits:(CGSize)size;     // return 'best' size to fit given size. does not actually resize view. Default is return existing view size

上面是苹果的方法说明。

sizeToFit 方法会返回一个苹果自带方法计算出的合适的宽高,即使你初始化的时候的宽和高设置错误,苹果也会给你算出一个合适的size让你填充你的内容。

-(void)addSizeToFitHelloLable{
    
    UILabel * hello = [[UILabel alloc]initWithFrame:CGRectMake(20, 20, 20, 100)];
    hello.text = @"hello world";
    hello.backgroundColor = [UIColor redColor];
    [self.view addSubview:hello];
    [hello sizeToFit];
    
}

我这里设置的宽度和高度明显是不对的,但是当我调用sizeToFit之后就好多了,下面是调用前和调用之后的对比效果。

  • 调用之前
    屏幕快照 2018-11-27 下午3.23.49

  • 调用之后
    屏幕快照 2018-11-27 下午3.23.06

因为sizeToFit之后内部会调用调用sizeThatFits,所以还可以在自定义view当中重写sizeThatFits方法,去调整sizeToFit之后的size。

----------customLable.m-------------
-(CGSize)sizeThatFits:(CGSize)size{
    
    [super sizeThatFits:size];
    size.height = 40;
    return size;
    
}

注意

添加自定义的lable到view上最后千万不能忘记调用sizeToFit方法,要不然内部重写的sizeThatFits不生效。

-(void)addCustomeSizeThatFitLable{
    
    CustomLable * hello = [[CustomLable alloc]initWithFrame:CGRectMake(20, 20, 200, 100)];
    hello.text = @"hello world";
    hello.backgroundColor = [UIColor redColor];
    [self.view addSubview:hello];
    [hello sizeToFit]; 
}
2018/7/20 posted in  iOS

运行时交换方法

+(void)load{
    Class class = self;
    
    SEL fromSelector = @selector(viewDidLoad);
    
    SEL toSelector = @selector(mwviewDidLoad);

    Method fromMethod = class_getInstanceMethod(class, fromSelector);
    Method toMethod = class_getInstanceMethod(class, toSelector);
    
    if(class_addMethod(class, fromSelector, method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
        class_replaceMethod(class, toSelector, method_getImplementation(fromMethod), method_getTypeEncoding(fromMethod));
    } else {
        method_exchangeImplementations(fromMethod, toMethod);
    }

    
}

-(void)mwviewDidLoad{
    
    NSLog(@"hello world from mwviewDidLoad");
    [self mwviewDidLoad];
    
}
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"hello world from viewDidLoad");

    // Do any additional setup after loading the view, typically from a nib.
}

打印结果为

2019-03-26 15:06:35.542596+0800 ExchangeMethod[48714:4112036] hello world from mwviewDidLoad
2019-03-26 15:06:35.542847+0800 ExchangeMethod[48714:4112036] hello world from viewDidLoad

注意千万不能手误
千万不能把[self mwviewDidLoad];改成[self viewDidLoad];

因为交换方法只会交换一次,实现交换了方法,调用viewDidLoad的时候其实实际是调用的本身mwviewDidLoad,往下走就又会调用本身,造成死循环。

2018/7/20 posted in  iOS

Building Apps with Dynamic Type

使用动态类型,人们可以选择自己喜欢的文本大小,iOS会根据需要自动切换字体。理解为什么动态类型很重要,以及在显示文本时如何支持它。了解iOS 11的新特性,掌握支持应用程序动态类型的框架和工具。

1.What is Dynamic Type?

Dynamic Type是一个允许用户在屏幕上自定义字体大小的功能。

屏幕快照 2018-12-13 下午6.37.58

对于视力有障碍的人来说区别很大,字体大之后就可以看到内容了。

2.What's New in iOS 11?

目标

  1. 字体要足够大
  2. 文字要完全,不允许截断
  3. UI还要依然美丽

使用说明和一些 API

  • 如何将字体和Dynamic type 一致
  • 适应更大的字体
  • Table views
  • Images

2.1如何将字体和Dynamic type 一致

通过文字样式TextStyle

  • 系统字体

    • xib 设置

    Artboard 2@3x

    • 代码设置
    UILabel * tip = [[UILabel alloc]init];
    [tip setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]];
    [tip setAdjustsFontForContentSizeCategory:YES];
  • 自定义字体
    上面说的是系统字体的时候可以跟随系统设置变大缩小,同样其他的自定义字体也可以通过UIFontMetrics达到一样的效果。

    UILabel * tip = [[UILabel alloc]init];
    [tip setFont:[[UIFontMetrics metricsForTextStyle:UIFontTextStyleBody] scaledFontForFont:customeFont]]
    [tip setAdjustsFontForContentSizeCategory:YES];

    Web Views实现跟随字体改变

    屏幕快照 2018-12-13 下午7.10.45

    当然这个只能适应于苹果设备,其他设备使用 rem

2.2 怎么适应大字体在屏幕上

  • 2.2.1 问题解答

    Q:如何解决文字变大后超出屏幕或者简单截断之后用户无法识别呢
    A:分为多行显示
    S:设置Label的 numberOflines = 0

    Q:之前设置的固定间距(比如设置LabelB的底部距离LabelA的底部40px),随着字体变大之后文本内容发生重叠

    Artboard 3@2x

    A1:设置LabelA的底部距离LabelB 的底部40px
    间距不变 但是是往不同方向方法
    修改后@2x

    A2:设置动态间距(iOS11以后可用)
    间距会随之变大
    屏幕快照 2018-12-14 上午11.06.14

    两种方案实现的效果不一样,如下所示。

    前后对比图@2x

  • 2.2.2 缩放值 Scaled Values

    缩放某个值,对于整体UI随着 large Text 来说有很重要的效果,会使整个UI看起来更协调。

    比如你之前是这么改变 y 值
    frame.origin.y +=40;

    现在你可以这么设置,constantVaule:40会根据系统设置而动态改变大小。

    frame.y += [[UIFontMetrics defaultMetrics] scaledValueForValue:40];

  • 2.2.3 并排文字的处理

    布局对比

    由上图可见,如果出现了文字变大的情况,如果不作任何处理会出现文字被截断的情况,直接影响了体验,如果只是简单的换行处理,会影响到美观,那么就可以垂直布置,横向沾满整个视图空间。

    通过函数[[UIApplication sharedApplication] preferredContentSizeCategory]orself.view.traitCollection.preferredContentSizeCategory获取用户的字体设置从UIContentSizeCategoryExtraSmallUIContentSizeCategoryExtraExtraLarge

    辅助设置的 largetext 的范围会有所区分会加上Accessibility比如UIContentSizeCategoryAccessibilityMedium

    所以在代码中就可以加上类似判断,判断当前的值是否大于某个界面改变的值,不同情形下布局结构不同。

    if (self.view.traitCollection.preferredContentSizeCategory > UIContentSizeCategoryLarge ) {
        //垂直布局
    }else{
    //并排布局
    }

2.3 Table views

如果你使用自带的 tableViewCell 那么就会自动布局,换行什么的完全不用你去担心。但是自定义 cell 的情况要自己去适配。

  • 2.3.1 Self-Sizing Table View Cells

    • 使用苹果默认设置的cell 样式

      • tableview 问每个 cell 提供高度
      • 提供一个预估的高度给那些在屏幕外的 cell

      如果必要就打开 self-sizing

      tableView.rowHeight = UITableViewAutomaticDimension
      tableView.estimatedRowHeight = 一个预估值
      

      如果有 sectionhead 或 sectionfooter

      self.tableView.estimatedSectionHeaderHeight = 20;
      self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
      self.tableView.estimatedSectionFooterHeight = 20;
      self.tableView.sectionFooterHeight = UITableViewAutomaticDimension;
    • 使用自定义cell 样式并使用 autolayout

      如果你使用自定义 cell 并使用 autolayout 很容易就可以使用 self-sizing,你只要设置好约束条件,使他们来定义单元的大小,然后 autolayout 会给你找到合适的大小。

    • 使用自定义cell 样式不使用 autolayout

      • 重写 sizeThatFits 的方法返回正确的高度
      • 使用 contentView.bounds.size.width 限定宽度

2.4 Images

在放大文字内容的同时也要保证图片的可辨识度,而不是只是布局改变了,但是非常小不易于观察。

2.4.1 imageView
  • 使用 PDF 图片并且在 asset catalog 勾选Perserve Vector Data 或者不使用PDF图像,提供更大的版本@1x@2x@3x
  • imageView.adjustImageSizeForAceeseeibilityContentSizeCategory = Yes
  • xib勾选 imageview放大图片 Adjusts Image Size
2.4.2 长按放大 tabbarItem 的图片

屏幕快照 2018-12-14 下午3.47.06

  • 使用 PDF 图片并且在 asset catalog 勾选Perserve Vector Data并选择 single scale

    屏幕快照 2018-12-14 下午4.57.58

  • 如果不使用PDF图像,提供更大的版本并在xib 为bar Item设置 aceessibility 图片或者在代码设置barItem.largeContentSizeImage = largeImage;

Tips
  • 使用 PDF 图像可以保证@1x @2x @3x 使用同一个图像进行缩放。

  • Xcode -> Accessbility inspector(方便进行字体大小的调整)
    屏幕快照 2018-12-14 下午5.12.49

2018/7/15 posted in  iOS

iOS UICollectionView刷新时闪屏的解决方法

在做相册的时候遇到了一个问题,就是UICollectionView刷新的时候会闪屏,网上搜了搜,解决的方法也是挺多,并没有一一尝试,只是存下来做个笔记,来看看遇到的几种方法。

方法一:

[UIView performWithoutAnimation:^{ 
   //刷新界面 
    [self.collectionView reloadData]; 
 }];

把刷新界面的事件放在这个BLock里就可以了!

方法二

  [collectionView performBatchUpdates:^{ 
    [collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]]; 
  } completion:nil]; 
}];

方法三

[self.trackPanel performBatchUpdates:^{ 
  [collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]]; 
} completion:^(BOOL finished) { 
  [UIView setAnimationsEnabled:YES]; 
}];

如果你的APP只支持iOS7+,推荐使用第一种方式performWithoutAnimation简单方便。

上面说的方法只能解决UIView的Animation,但是如果你的cell中还包含有CALayer的动画,比如这样:

- (void)layoutSubviews{
  [super layoutSubviews];
   
  self.frameLayer.frame = self.frameView.bounds;
}

上述情况多用于自定义控件使用了layer.mask的情况,如果有这种情况,上面提到的方法是无法取消CALayer的动画的,但是解决办法也很简单:

  [super layoutSubviews];
   
  [CATransaction begin];
  [CATransaction setDisableActions:YES];
   
  self.frameLayer.frame = self.frameView.bounds;
   
  [CATransaction commit];  
}

2018/7/14 posted in  iOS

对比Texture中Node和UIKit中View

node.view和view的差别

再一次深刻的体会到了node.view和view的差别。

最开始一直以为node.view就类似于ASTableNode对应的UITableview

其实远远没有那么简单,并不是那么的一个对应的关系.
必须要把一些subnode都包到一个node里面最后这个node的view对应的是这些subnode的集合。

如果只是

ASDisplayNode * node = [[ASDisplayNode alloc]init];
ASDisplayNode * subnode = [ASDisplayNode new];
ASTextNode * textnode = [ASTextNode new];                    
ASButtonNode * buttonnode = [ASButtonNode new];
[node addSubnode:subnode];
[node addSubnode:textnode];
[node addSubnode:buttonnode];

我是在给tableview添加node为tableHeaderView发现的这个问题
后面新建一个node 把这些subnode都包进去问题就解决了。

这个时候把node.view 当成这三个subnode的集合就会出现问题

阴影以及圆角的设置

在使用UIview添加阴影以及同时添加圆角的时候不能设.clipsToBounds = YES
但是切圆角的时候就需要设置.clipsToBounds = YES
当时的做法也是最外层放置一个UIView的壳子,让外层的.clipsTobounds = NO 里面的.clipsTobounds = YES
在外边的view添加阴影的效果。

使用node的时候也是这样的原理。

2018/7/11 posted in  iOS

如何理解多线程中的队列

func asyncmethod()  {
        DispatchQueue.global().async {
            
            DispatchQueue.main.sync {
                print("DispatchQueue.main.sync task \(Thread.current)")

            }

            print("DispatchQueue.global().async task \(Thread.current)")
        }
    }

DispatchQueue.main.sync必须用于在全局队列当中,因为async执行是异步操作。不能单独使用,因为这步操作会阻塞当前线程 执行完线程中的操作之后才会继续向下执行。

同步和异步在这里是线程概念,同步不会创建新的线程,会阻塞当前的线程在这个线程里执行任务。而异步则不会阻塞当前线程,会选择在恰当的时机在当前线程或者另开线程执行任务(看系统如何调度),开始任务和完成任务时间是不确定的。

串行队列,后一个任务等待前一任务结束后再执行,按添加顺序一个一个执行。

并行队列,后一个任务不会等待前一个任务,不等前一个任务完成就会分配新任务。

串行和并行,这里对应的是队列的概念。队列负责管理多个任务,队列拥有一个线程池,池子里有一个或者多个线程,它按要求将每个任务调度到某一个线程执行。

override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "show Red", style: .plain, target: self, action: #selector(pushToRed))
        print("thread is  \(Thread.current)")

        DispatchQueue.global().sync {
            print("thread is  \(Thread.current)")

            DispatchQueue.global().sync {
                print("thread is  \(Thread.current)")

                print("1")
                print("2")
                print("3")
                print("4")
                print("5")
                print("6")
                print("7")
            }
            
        }
//        asyncmethod()
        
        // Do any additional setup after loading the view.
    }
thread is  <NSThread: 0x60000297aac0>{number = 1, name = main}
thread is  <NSThread: 0x60000297aac0>{number = 1, name = main}
thread is  <NSThread: 0x60000297aac0>{number = 1, name = main}
1
2
3
4
5
6
7

所以并不是说全局队列中的任务就不能在主线程执行,事实证明还是可以的。

2018/7/11 posted in  iOS