美文网首页
iOS开发知识点总结(一)

iOS开发知识点总结(一)

作者: SuAdrenine | 来源:发表于2017-11-22 22:08 被阅读11次

1、获取当前系统版本号

CGFloat sysVersion = [[[UIDevice currentDevice] systemVersion] floatValue];

2、串行与并行,同步与异步

  • 串行同步:任务按顺序执行,按顺序结束,整个过程只会开一条线程。
  • 串行异步:任务按顺序执行,按顺序结束,因为是串行所以也只会开一条线程。
  • 并行同步:任务不按顺序执行,不按顺序结束,整个过程只开一条线程。
  • 并行异步:任务不按顺序执行,不按顺序结束,整个过程可能有多条线程。

总结:同步异步描述的是当前线程或代码流是否要阻塞以等待加入队列的任务执行完毕:同步要阻塞当前线程;异步不会阻塞当前线程。串行和并行描述的时队列里各个任务是否可以并发执行:串行队列里的任务不能并发执行,只能一个接一个地执行,同一时刻该串行队列里的任务最多只有一个在执行;并发队列里的任务后面的任务不必等待前面的任务执行完毕再执行,可以多个同时执行,同一时刻该并行队列里的任务可以有多个正在执行。

简言之:同步异步要不要等(会不会阻塞),串行并行能不能多任务同时进行

3、在一个viewController中添加多个ViewController

//添加一个 child view controller
- (void)addSubVC {
  SubController *sub = [[SubController alloc] init];
  [self addChildViewController:sub];
  sub.view.frame = CGRectMake(0, 100, 320, 100);
  [self.view addSubview:sub.view];
  self.view.clipsToBounds = NO;
  [sub didMoveToParentViewController:self];  // 子vc被通知现在有了一个父控制器
}
//移除一个 child view controller
- (void)deleteSubVC {
  [vc willMoveToParentViewController:nil];
  [vc.view removeFromSuperview];
  [vc removeFromParentViewController];
}

4、NSDate、NSDateFormatter和NSCalendar组合使用:

NSString *str = @"2018-02-03 19:09:09 +0000";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];;
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";
NSDate *date = [formatter dateFromString:str];//string转date

NSDate *now = [NSDate date];  //获取当前date
    
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit type = NSCalendarUnitYear |
                        NSCalendarUnitMonth |
                        NSCalendarUnitDay |
                        NSCalendarUnitHour |
                        NSCalendarUnitMinute |
                        NSCalendarUnitSecond;
NSDateComponents *cmps = [calendar components:type fromDate:date toDate:now options:0];  //计算时间差
NSLog(@"两时间相差:%ld年%ld月%ld日%ld时%ld分%ld秒",cmps.year,cmps.month,cmps.day,cmps.hour,cmps.minute,cmps.second);

5、图片区域拉伸

方法一:

// 处理区域拉伸的图片 
UIImageView *handleImg = [[UIImageView alloc] initWithFrame:CGRectMake(100, 200, 200, 100)]; 
UIImage *img = [UIImage imageNamed:@"theImage"]; 
// 四个数值对应图片中距离上、左、下、右边界的不拉伸部分的范围宽度 ,也就是对中间部分进行拉伸
img = [img resizableImageWithCapInsets:UIEdgeInsetsMake(35, 35, 35, 35) resizingMode:UIImageResizingModeStretch];
handleImg.image = img; 
[self.view addSubview:handleImg];

方法二:

UIImage *img=[UIImage imageNamed:@"imageName"];
//设置不拉伸区域,左边15个单位,上边12个单位不拉伸,其余位置拉伸
img=[img stretchableImageWithLeftCapWidth:15 topCapHeight:12];
UIImageView *imgView=[[UIImageView alloc] initWithImage:img];
[imgView setFrame:CGRectMake(10, 10, 200, 200)];
[self. view addSubview:imgView];

6、监听文本框编辑状态

  • 代理(原则上自己不要成为自己的代理)
  • 通知
  • target

target方式:

//开始编辑
[self addTarget:self action:@selector(editBegain:) forControlEvents:UIControlEventEditingDidBegin];  //自己实现editBegain方法
//结束编辑
[self addTarget:self action:@selector(editEnd:) forControlEvents:UIControlEventEditingDidEnd];  //自己实现editEnd方法

7、字符串拼接

NSString *string=@""; // 结果字符串
NSString *string1=@"a", string2=@"b"; //已存在的字符串,需要将string1和string2连接起来

//方法1
string = [NSString initWithFormat:@"%@,%@", string1, string2];

//方法2
string = [string1 stringByAppendingString:string2];

//方法3 
string = [string stringByAppendingFormat:@"%@,%@",string1, string2];

8、等待多个请求结束(多个请求结束顺序未知)

dispatch_group_t group =  dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // 执行1个耗时的异步操作
});

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // 执行1个耗时的异步操作
});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
      // 等前面的异步操作都执行完毕后,回到主线程...
});

9、等待多个请求结束(多个任务顺序结束)

dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);

//任务一
[self loadDataOneWithCompeteBlock:^(BOOL suc){
  if (suc) {
    dispatch_group_leave(group);
  }
}];

//任务二
dispatch_group_enter(group);
[self loadDataTwoWithCompeteBlock:^(BOOL suc){
  if (suc) {
    dispatch_group_leave(group);
  }
}];

//任务三
dispatch_group_enter(group);
  [self loadDataThreeWithCompeteBlock:^(BOOL suc){
  if (suc) {
    dispatch_group_leave(group);
  }  
}];

//通知任务一二三结束
dispatch_group_notify(group, GCD_MAINQUEUE, ^{
  //任务结束

});

10、分组完成任务,前面的组比后面的组先完成任务

dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);

    dispatch_async(queue, ^{
        NSLog(@"----任务 1-----");
    });

    dispatch_async(queue, ^{
        NSLog(@"----任务 2-----");
    });    

    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----");
    });

    dispatch_async(queue, ^{
        NSLog(@"----任务 3-----");
    });

    dispatch_async(queue, ^{
        NSLog(@"----任务 4-----");
    });

任务1,2一定会先于任务3,4完成

11、获取当前ViewController

#pragma mark - 获取当前屏幕显示的ViewController
+ (UIViewController *)getCurrentViewController
{
    UIViewController *result = nil;

    UIWindow * window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal)
    {
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(UIWindow * tmpWin in windows)
        {
            if (tmpWin.windowLevel == UIWindowLevelNormal)
            {
                window = tmpWin;
                break;
            }
        }
    }
    UIView *frontView = [[window subviews] objectAtIndex:0];
    id nextResponder = [frontView nextResponder];

    if ([nextResponder isKindOfClass:[UIViewController class]])
        result = nextResponder;
    else
        result = window.rootViewController;

    return result;
}
#pragma mark - 获取view所在的ViewController
+ (UIViewController *)findViewController:(UIView *)sourceView
{
    id target = sourceView;
    while (target) {
        target = ((UIResponder *)target).nextResponder;
        if ([target isKindOfClass:[UIViewController class]]) {
            break;
        }
    }
    return target;
}

12、iOS开发实战之设置图片圆角的两种方式

方法一
imageView.layer.cornerRadius = width/2;  //imageView是正方形,此时角度设为width或height的一半
imageView.layer.masksToBouds = YES;

PS:这种方法比较常用,但是在iOS9.0以下存在一个问题,比如一个tableView上存在过多使用这样设置圆角的图片,会造成FPS下降,iOS9.0官方修复了这个问题

方法二
//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 drawAtPotnt:CGPointZero];
//5、取出图片
image = UIGraphicsGetImageFromCurrentImageContext();
//6、关闭上下文
UIGraphiceEndImageContext();
//7、给imageView赋值
imageView.image = image;

13、设置UIView特定几个角为圆角

如果需要将UIView的4个角全部都为圆角,做法相当简单,只需设置其Layer的cornerRadius属性即可(项目需要使用QuartzCore框架)。而若要指定某几个角(小于4)为圆角而别的不变时,这种方法就不好用了。
对于这种情况,Stackoverflow上提供了几种解决方案。其中最简单优雅的方案,就是使用UIBezierPath。下面给出一段示例代码。

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(120, 10, 80, 80)];
view.backgroundColor = [UIColor redColor];
[self.view addSubview:view]; 
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds 
  byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight 
  cornerRadii:CGSizeMake(10, 10)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = view.bounds;
maskLayer.path = maskPath.CGPath;
view.layer.mask = maskLayer;

其中,

byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight

指定了需要成为圆角的角。该参数是UIRectCorner类型的,可选的值有:

* UIRectCornerTopLeft
* UIRectCornerTopRight
* UIRectCornerBottomLeft
* UIRectCornerBottomRight
* UIRectCornerAllCorners

从名字很容易看出来代表的意思,使用“|”来组合就好了。

14、使用Git提交提示冲突

用git pull来更新代码的时候,遇到了下面的问题:

error: Your local changes to the following files would be overwritten by merge:
    xxx/xxx/xxx.m
Please, commit your changes or stash them before you can merge.
Aborting

出现这个问题的原因是其他人修改了xxx.php并提交到版本库中去了,而你本地也修改了xxx.php,这时候你进行git pull操作就好出现冲突了,解决方法,在上面的提示中也说的很明确了。

1)、保留本地的修改的改法

保留本地修改,先备份,然后从服务端down下新版本,再恢复本地修改

git stash
git pull
git stash pop

通过git stash将工作区恢复到上次提交的内容,同时备份本地所做的修改,之后就可以正常git pull了,git pull完成后,执行git stash pop将之前本地做的修改应用到当前工作区。

  • git stash: 备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。
  • git stash pop: 从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。
  • git stash list: 显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。
  • git stash clear: 清空Git栈。此时使用gitg等图形化工具会发现,原来stash的哪些节点都消失了。
2)、放弃本地修改 的改法(不推荐)
git reset --hard
git pull

15、Git撤销某个commit

在使用git时,push到远端后发现commit了一些多余的文件,或者希望能够回退到以前的版本。
先在本地回退到相应的版本(选一个命令即可):

git reset --mixed <版本号>:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,回退commit和index信息
git reset --soft <版本号>:回退到某个版本,只回退了commit的信息,保留当前工作区的修改。如果还要提交,直接commit即可
git reset  --hard <版本号>:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,抛弃当前工作区的修改,此命令 慎用!

如果此时使用命令:

git push origin <分支名>

会提示本地的版本落后于远端的版本;
为了覆盖掉远端的版本信息,使远端的仓库也回退到相应的版本,需要加上参数--force

git push origin <分支名> --force

16、tableView上面多出来20个像素

因为自动布局的缘故,设置一下属性就可以解决问题

self.edgesForExtendedLayout = UIRectEdgeNone;

17、KVC的读取与设置规则

KVC使用起来比较简单,但是它如何查找一个属性进行读取呢?具体查找规则(假设现在要利用KVC对a进行读取):
如果是动态设置属性,则优先考虑调用setA方法,如果没有该方法则优先考虑搜索成员变量_a,如果仍然不存在则搜索成员变量a,如果最后仍然没搜索到则会调用这个类的setValue:forUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确设置);
如果是动态读取属性,则优先考虑调用a方法(属性a的getter方法),如果没有搜索到则会优先搜索成员变量_a,如果仍然不存在则搜索成员变量a,如果最后仍然没搜索到则会调用这个类的valueforUndefinedKey:方法(注意搜索过程中不管这些方法、成员变量是私有的还是公共的都能正确读取);

18、MRC环境下集合中对象的内存管理:

Person *p = [Person new];  //引用计数1
//NSMutableArray *mutArr = [NSMutableArray array];//这个方法会自动管理mutArr的内存,下面这个不会
NSMutableArray *mutArr = [[NSMutableArray alloc] init];
[mutArr addObject:p];//引用计数2
[p release];//引用计数1
[mutArr removeObject:p];//引用计数0,p可以被释放

总结:

  • 如果将一个对象添加到一个数组中,那么这个数组会对对象进行一次retain;
  • 当数组对象被释放以后,数组对象会给数组里面所有对象都发送一条release消息;
  • 当数组移除一个对象的时候,会给这个对象发送一条release消息;

19、Copy与MutableCopy

  • 使用copy的前提是对象遵循了NSCopying/NSMutableCopying协议以及实现了copyWithZone:/mutableCopyWithZone:方法
  • 一个对象可以使用copy和mutableCopy来产生一个副本;
  • copy产生的是一个不可变的副本,mutableCopy产生的是一个可变的副本;

原则:拷贝的对象要和原对象的值相同;修改任意一个不改变另一个。
示例:
1)、使用mutableCopy拷贝一个不可变对象生成一个可变对象

- (void)testCode {
    NSString *srcStr = @"test";
    NSMutableString *copyStr = [srcStr mutableCopy];
    NSLog(@"src: %@, copy: %@",srcStr,copyStr);
    NSLog(@"src: %p, copy: %p",srcStr,copyStr);
}

2)、使用mutableCopy拷贝一个可变对象生成一个可变对象

- (void)testCode {
    NSMutableString *srcStr = [NSMutableString stringWithFormat:@"test"];
    NSMutableString *copyStr = [srcStr mutableCopy];
    [srcStr appendString:@"change"];
    NSLog(@"src: %@, copy: %@",srcStr,copyStr);
    NSLog(@"src: %p, copy: %p",srcStr,copyStr);
}

3)、使用copy拷贝一个可变对象生成一个不可变对象

- (void)testCode {
    NSMutableString *srcStr = [[NSMutableString alloc] initWithString:@"test"];
    NSString *copyStr = [srcStr copy];
    [srcStr appendString:@"change"];
    NSLog(@"src: %@, copy: %@",srcStr,copyStr);
    NSLog(@"src: %p, copy: %p",srcStr,copyStr);
}

4)、使用copy拷贝一个不可变的对象指向原对象,不会生成一个新对象

- (void)testCode {
    NSString *srcStr = @"test";
    NSString *copyStr = [srcStr copy];
    
    NSLog(@"src: %@, copy: %@",srcStr,copyStr);
    NSLog(@"src: %p, copy: %p",srcStr,copyStr);
}

注意:
因为使用copy的时候会生成一个新的对象有时候不会生成新的对象,
所以如果没有新的对象生成,我们称之为浅拷贝,指针拷贝,生成了一个新的对象,我们称之为深拷贝。
总结:不可变对象调用copy的是浅拷贝,其余都是深拷贝。

20、Block中的copy(MRC环境下)

1)、block在栈与堆中
Person *p = [Person new];
NSLog("%ld",[p retainCount]);//1
void (^myBlock) {//block在栈中
  NSLog("%@",p);
  NSLog("%ld",[p retainCount]);
}
Block_copy(myBlcok);  //block移到堆中(ARC编译器会将block自动移到堆中)

小节:

  • 默认block在栈中,引用外界对象,不会对其进行引用+1
  • 使用copy将block移到堆中(不会进行拷贝),引用外界对象,会对其进行引用+1
2)、对block使用copy,可以保存block中对其他对象的引用,防止block调用的时候,引用的对象已经被释放的问题;
3)、copy block之后引发的循环引用:

如果对象的block中又使用到了对象本身,会引发循环引用,在MRC环境下,需要使用__block修饰这个对象,去除循环引用

相关文章

网友评论

      本文标题:iOS开发知识点总结(一)

      本文链接:https://www.haomeiwen.com/subject/xqenkxtx.html