iOS-OC常见技术点整理

作者: Simple_Code | 来源:发表于2017-10-25 23:20 被阅读25次
    1. 移除控件上所有得子控件
    方法一:
    [view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    
    方法二:
    - (void)removeAllSubviews {
    //[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
    while (self.subviews.count) {
    [self.subviews.lastObject removeFromSuperview];
    }
    }
    
    方法三:
    [xxxView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [obj removeFromSuperview];
    }];
    
    2. 直接滚动到Scrollview的底部
    - (void)scrollsToBottomAnimated:(BOOL)animated
    {
        CGFloat offset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
        if (offset > 0)
        {
            [self.tableView setContentOffset:CGPointMake(0, offset) animated:animated];
        }
    }
    
    3. 给Label文字添加行距和文字距离+计算其高度
    #define UILABEL_LINE_SPACE  6
    #define HEIGHT [ [ UIScreen mainScreen ] bounds ].size.height
    //给UILabel设置行间距和字间距
    -(void)setLabelSpace:(UILabel*)label withValue:(NSString*)str withFont:(UIFont*)font {
        NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStylealloc] init];
        paraStyle.lineBreakMode =NSLineBreakByCharWrapping;
        paraStyle.alignment =NSTextAlignmentLeft;
        paraStyle.lineSpacing = UILABEL_LINE_SPACE; //设置行间距
        paraStyle.hyphenationFactor = 1.0;
        paraStyle.firstLineHeadIndent =0.0;
        paraStyle.paragraphSpacingBefore =0.0;
        paraStyle.headIndent = 0;
        paraStyle.tailIndent = 0;
        //设置字间距 NSKernAttributeName:@1.5f
        NSDictionary *dic =@{NSFontAttributeName:font,NSParagraphStyleAttributeName:paraStyle,NSKernAttributeName:@1.5f
    };
        NSAttributedString *attributeStr = [[NSAttributedStringalloc] initWithString:strattributes:dic];
        label.attributedText = attributeStr;
    }
    
    //计算UILabel的高度(带有行间距的情况)
    -(CGFloat)getSpaceLabelHeight:(NSString*)str withFont:(UIFont*)font withWidth:(CGFloat)width {
        NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStylealloc] init];
        paraStyle.lineBreakMode =NSLineBreakByCharWrapping;
        paraStyle.alignment =NSTextAlignmentLeft;
        paraStyle.lineSpacing = UILABEL_LINE_SPACE;
        paraStyle.hyphenationFactor = 1.0;
        paraStyle.firstLineHeadIndent =0.0;
        paraStyle.paragraphSpacingBefore =0.0;
        paraStyle.headIndent = 0;
        paraStyle.tailIndent = 0;
        NSDictionary *dic =@{NSFontAttributeName:font,NSParagraphStyleAttributeName:paraStyle,NSKernAttributeName:@1.5f
    };
        CGSize size = [strboundingRectWithSize:CGSizeMake(width,HEIGHT) options:NSStringDrawingUsesLineFragmentOriginattributes:dic context:nil].size;
        return size.height;
    }
    
    4. 使用Masonry后、使frame及时生效(需要在mas_makeConstraints之后用它的父视图调用layoutIfNeeded可以使得约束立即生效)
        UIView *view   =   [UIView new];
        [self.view addSubview:view];
        [view1 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(10, 10, 10, 10));
        }];
        view.backgroundColor   =   [UIColor redColor];
        [self.view layoutIfNeeded];
        NSLog(@"%@",view1.description);
    
    5. 自定义View的淡入淡出
    //  淡入
    
    - (void)fadeIn
    {
        self.transform = CGAffineTransformMakeScale(1.3, 1.3);
        self.alpha = 0;
        [UIView animateWithDuration:.35 animations:^{
            self.alpha = 1;
            self.transform = CGAffineTransformMakeScale(1, 1);
        }];
    }
    
    // 淡出
    
    - (void)fadeOut
    {
        [UIView animateWithDuration:.35 animations:^{
            self.transform = CGAffineTransformMakeScale(1.3, 1.3);
            self.alpha = 0.0;
        } completion:^(BOOL finished) {
            if (finished) {
                [self removeFromSuperview];
            }
        }];
    }
    
    // 向上弹起
    
    - (void)show{
        UIWindow *currentWindows = [UIApplication sharedApplication].keyWindow;
        self.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.2];
        [currentWindows addSubview:self];
        
        [UIView animateWithDuration:.3 animations:^{
            [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
            self.backView.frame = ScreenBounds;
        }];
    }
    
    // 向下弹出
    
    - (void)dissMissView{
        
        [UIView animateWithDuration:.3 animations:^{
            [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
            self.backView.frame = CGRectMake(0, ScreenHeight, ScreenWidth, ScreenHeight);
        } completion:^(BOOL finished) {
            [self removeFromSuperview];
        }];
    }
    
    6. 图片拉伸方法(- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode)的使用
    /**
      参数一:capInsets是UIEdgeInsets类型的数据,即原始图像要被保护的区域
      参数二:resizingMode是UIImageResizingMode类似的数据,即图像拉伸时选用的拉伸模式
             UIImageResizingModeTile,     平铺 
             UIImageResizingModeStretch,  拉伸
    */
    - (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode
    
    
    拉伸区域示意图.png
    7. iOS中超出父视图的按钮点击事件响应处理(方法一有问题)

    方法一:

    //在父控件里面重写此方法、self.launchBtn为当前控件
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
         
        UIView * view = [super hitTest:point withEvent:event];
        if (view == nil) {
            // 转换坐标系
            CGPoint newPoint = [self.launchBtn convertPoint:point fromView:self];
            // 判断触摸点是否在button上
            if (CGRectContainsPoint(self.launchBtn.bounds, newPoint)) {
                view = self.launchBtn;
            }
        }
        return view;
    }
    

    方法二:

    //重写hitTest方法,去监听发布按钮的点击,目的是为了让凸出的部分点击也有反应
    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        
        //这一个判断是关键,不判断的话push到其他页面,点击发布按钮的位置也是会有反应的,这样就不好了
        //self.isHidden == NO 说明当前页面是有tabbar的,那么肯定是在导航控制器的根控制器页面
        //在导航控制器根控制器页面,那么我们就需要判断手指点击的位置是否在发布按钮身上
        //是的话让发布按钮自己处理点击事件,不是的话让系统去处理点击事件就可以了
        if (self.isHidden == NO) {
            
            //将当前tabbar的触摸点转换坐标系,转换到发布按钮的身上,生成一个新的点
            CGPoint newP = [self convertPoint:point toView:self.publishButton];
            
            //判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮
            if ( [self.publishButton pointInside:newP withEvent:event]) {
                return self.publishButton;
            }else{//如果点不在发布按钮身上,直接让系统处理就可以了
                return [super hitTest:point withEvent:event];
            }
        }
        else {//tabbar隐藏了,那么说明已经push到其他的页面了,这个时候还是让系统去判断最合适的view处理就好了
            return [super hitTest:point withEvent:event];
        }
    }
    
    8. 获得Xcode里面所有字体的字体样式
    // 获取字体样式
        NSArray *familyNames = [UIFont familyNames];
        for( NSString *familyName in familyNames )
        {
            NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName];
            for( NSString *fontName in fontNames )
            {
                printf( "\tFont: %s \n", [fontName UTF8String] );
            }
        }
       
    // 使用字体 
        self.label.text = @"login";
        self.label.font = [UIFont fontWithName:@"Century-GothicT." size:30];
    
    9. Xcode里面中文文字设置斜体
     // ios中不支持中文倾斜,于是只有设置倾斜角度。
        
        // 第一行代码:设置反射。倾斜15度。
        CGAffineTransform matrix = CGAffineTransformMake(1,0,tanf(15*(CGFloat)M_PI/180),1,0,0);
        
        // 第二行代码:取得系统字符并设置反射。
        UIFontDescriptor *desc = [ UIFontDescriptor fontDescriptorWithName:[UIFont  systemFontOfSize :17 ]. fontName matrix :matrix];
        
        // 第三行代码:获取字体。
        UIFont *font = [UIFont fontWithDescriptor:desc size :17];
    
    10. + initialize 与 +load调用时机

    load 方法会在加载类的时候就被调用,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法。
    initialize 方法类似一个懒加载,如果没有使用这个类,那么系统默认不会去调用这个方法,且默认只加载一次; initialize 的调用发生在 +init 方法之前。

    11. 更改webViewl里面html的字体样式
    NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"enLATP" ofType:@"html"];
    NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
    UIFont *font = [UIFont fontWithScaledSize:14];
    UIFont *font1 = [UIFont fontWithBigSize:16];
    NSString *fontColor = @"CCCCFF";
    NSString *fontColor1 = @"000000";
    
    NSString *htmlString =[NSString stringWithFormat:@"<html> \n"
                                       "<head> \n"
                                       "<style type=\"text/css\"> \n"
                                       "body {font-family: \"%@\"; color: %@;}\n"
                                       ".boldFont {font-family: \"%@\"; color: %@;}\n"
                                       "</style> \n"
                                       "</head> \n"
                                       "<body>%@</body> \n"
                                       "</html>", font.familyName,fontColor,font1.familyName,fontColor1,appHtml];
    
    if(htmlPath.length==0)
       {
           return;
        }
    NSURL *baseURL = [NSURL fileURLWithPath:htmlPath];
     [self.webView loadHTMLString:htmlString baseURL:baseURL];
    
    12. 点击屏幕键盘退出
    - (void)sp_addReturnKeyBoard {
        
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
        tap.numberOfTapsRequired = 1;
        tap.numberOfTouchesRequired = 1;
        [tap.rac_gestureSignal subscribeNext:^(id x) {
            
            AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
            [appDelegate.window endEditing:YES];
        }];
        [self addGestureRecognizer:tap];
    }
    
    13. 通知标准写法(建议使用)
    // Foo.h
    UIKIT_EXTERN NSNotificationName const ZOCFooDidBecomeBarNotification
     // Foo.m
    NSNotificationName const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification";
    
    14. 获取APP当前所在的ViewController
    - (UIViewController *)findBestViewController:(UIViewController*)vc {
        
        if (vc.presentedViewController) {
            
            // Return presented view controller
            return [self findBestViewController:vc.presentedViewController];
            
        } else if ([vc isKindOfClass:[UISplitViewController class]]) {
            
            // Return right hand side
            UISplitViewController* svc = (UISplitViewController*) vc;
            if (svc.viewControllers.count > 0)
                return [self findBestViewController:svc.viewControllers.lastObject];
            else
                return vc;
            
        } else if ([vc isKindOfClass:[UINavigationController class]]) {
            
            // Return top view
            UINavigationController* svc = (UINavigationController*) vc;
            if (svc.viewControllers.count > 0)
                return [self findBestViewController:svc.topViewController];
            else
                return vc;
            
        } else if ([vc isKindOfClass:[UITabBarController class]]) {
            
            // Return visible view
            UITabBarController* svc = (UITabBarController*) vc;
            if (svc.viewControllers.count > 0)
                return [self findBestViewController:svc.selectedViewController];
            else
                return vc;
            
        } else {
            
            // Unknown view controller type, return last child view controller
            return vc;
            
        }
    }
    - (UIViewController*) currentViewController {
        // Find best view controller
        UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
        return [self findBestViewController:viewController];
    }
    
    调用
    UIViewController * viewControllerNow = [self currentViewController];
     if ([viewControllerNow  isKindOfClass:[PCBConversationController class]]) {   //如果是页面XXX,则执行下面语句
                item.badgeValue = nil;
     }else{}      
    
    15. 通知的注册和移除
    -(void) viewWillAppear:(BOOL)animated 方法里面注册
    -(void) viewWillDisappear:(BOOL)animated;方法里面移除
    
    16.判断当前页面是Push过来还是present过来
    方法一:
    通过判断self有没有present方式显示的父视图presentingViewController
    
    if (self.presentingViewController) {
            [self dismissViewControllerAnimated:YES completion:nil];
        } else {
            [self.navigationController popViewControllerAnimated:YES];
        }
    
    方法二:(若果present的ControllView的带有UINavigationBar不能使用此方法)
    通过判断self有没有present方式显示的父视图
    
    if (self.navigationController.topViewController == self) {
            [self.navigationController popViewControllerAnimated:YES];
        } else {
            [self dismissViewControllerAnimated:YES completion:nil];
        }
    
    17. CollectioView滚动到指定section的方法

    https://www.cnblogs.com/tinych/p/5891665.html

    18.查看自己编写的代码行数
    1. cd到代码的文件夹下面
    2. 然后编辑一下命令
    find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.h" -or -name "*.rss" ")" -print | xargs wc -l
    
    19.新特性页面渐隐跳转到主页面
    #pragma mark - 使页面动态消失
    - (void)restoreRootViewController:(UIViewController *)rootViewController {
        
        [UIView transitionWithView:[UIApplication sharedApplication].keyWindow duration:0.5f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
            
            BOOL oldState = [UIView areAnimationsEnabled];
            [UIView setAnimationsEnabled:NO];
            [UIApplication sharedApplication].keyWindow.rootViewController = rootViewController;
            [UIView setAnimationsEnabled:oldState];
            
        } completion:nil];
    }
    

    使用方法

    // 设置跟控制器
        PCBLoginController *loginVc = [[PCBLoginController alloc]init];
        CTNavigationController *naVc = [[CTNavigationController alloc]initWithRootViewController:loginVc];
        
        // 切换控制器
        [self restoreRootViewController:naVc];
    

    使用CATransition方法达到此效果

        // 跳转到核心界面,push,modal,切换跟控制器的方法
        KeyWindow.rootViewController = [[TabBarController alloc] init];
        
        CATransition *anim = [CATransition animation];
        anim.duration = 0.5;
        anim.type = @"rippleffect";
        [KeyWindow.layer addAnimation:anim forKey:nil];
    
    20.货币价格计算,使用float类型运算,经常出现误差。

    在iOS开发中,经常遇到和货币价格计算相关的,这时就需要注意计算精度的问题。使用float类型运算,经常出现误差。为了解决这种问题我们使用NSDecimalNumber,下面将通过例子的形式给大家展示一下。
    点击查看

    21.解决APP切入到后台,倒计时停止的问题
     - (void)applicationDidEnterBackground:(UIApplication *)application {
        
        UIApplication *app = [UIApplication sharedApplication];
        __block UIBackgroundTaskIdentifier bgTask;
        bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
            dispatch_async(dispatch_get_main_queue(), ^{
                if (bgTask != UIBackgroundTaskInvalid){
                    bgTask = UIBackgroundTaskInvalid;
                }
            });
        }];
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                if (bgTask != UIBackgroundTaskInvalid){
                    bgTask = UIBackgroundTaskInvalid;
                }
            });
        });
    }
    
    22.ScrollView滚动动画的三种方式
    1. begin 和 commit
     [UIView beginAnimations:nil context: nil];
      [UIView setAnimationDuration:2.0];
      [UIView setAnimationDelegate:self]; // 代理
      [UIView setAnimationDidStopSelector:@selector(stop)];
      [UIView setAnimationWillStartSelector:@selector(start)];
    
      CGFloat offsetX = self.scrollView.contentSize.width - self.scrollView.frame.size.width;
      self.scrollView.contentOffset = CGPointMake(offsetX, self.scrollView.contentOffset.y);
    
      [UIView commitAnimations];
    
    1. block
    [UIView animateWithDuration:2.0 animations:^{
          self.scrollView.contentOffset = CGPointMake(0, self.scrollView.contentOffset.y);
    }];
    
    1. 某些属性有其特有的动画
    CGPoint offset = CGPointMake(self.scrollView.contentOffset.x, 0);
     [self.scrollView setContentOffset:offset animated:YES];
    
    23.RAC注销通知的两种方法

    方法一:

    //代替通知
      //takeUntil会接收一个signal,当signal触发后会把之前的信号释放掉
      [[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {
    
          NSLog(@"键盘弹出");
    
      }];
    

    方法二:

    //这里这样写只是为了给大家开拓一种思路,selector的方法可以应需求更改,即当这个方法执行后,产生一个信号告知控制器释放掉这个订阅的信号
      RACSignal * deallocSignal = [self rac_signalForSelector:@selector(viewWillDisappear:)];
    
      [[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"haha" object:nil] takeUntil:deallocSignal] subscribeNext:^(id x) {
    
          NSLog(@"haha");
    
      }];
    
    24.消除警告

    1.关于编译器:关闭警告:

    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    代码
    #pragma clang diagnostic pop
    

    2.忽略没用的变量

    #pragma unused (foo)
    明确定义错误和警告
    #error Whoa, buddy, you need to check for zero here!
    #warning Dude, don't compare floating point numbers like this!
    
    25.导航栏显示和隐藏(只能进行显示和隐藏两者之间的切换、不能进行隐藏和隐藏之间的切换(这个有bug))

    将animated属性继承ViewWillAppear(Disappear)的animated属性即可

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
        
        [self.navigationController setNavigationBarHidden:YES animated:animated];
    }
    
    - (void)viewWillDisappear:(BOOL)animated
    {
        [super viewWillDisappear:animated];
    
        [self.navigationController setNavigationBarHidden:NO animated:animated];
    }
    
    
    26.使用Masonry计算cell高度titleLabel为最下面元素
    //注意:这是写这篇文章的重中之重,核心代码
    + (CGFloat)heightWithModel:(ECHelpListModel *)model{
        ECHelpListDetailCell *cell = [[ECHelpListDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@""];
        [cell setModel:model];
        [cell layoutIfNeeded];
        return cell.titleLabel.bottom + 10;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        //取出model
        HHPollingItemsModel *model = self.items[indexPath.row];
        return [HHPollingDetailCell heightWithModel:model];
    }
    

    model 懒加载计算高度自己常用的方法

    //.h
    @property (nonatomic, assign) CGFloat cellHeight;
    //.m
    - (CGFloat)cellHeight {
        // 如果cell的高度已经计算过, 就直接返回
        if (_cellHeight) return _cellHeight;
        _cellHeight = 0;
        _cellHeight++......// 计算高度的一系列操作
         return _cellHeight;
    }
    
    //调用:
    //计算cell的高度(在model里面计算)
    return self.dataArray[indexPath.row].cellHeight;
    

    参考地址:http://www.cocoachina.com/ios/20171212/21504.html

    27.判断子view是否添加到父view上
     if ([subView isDescendantOfView: parentView]) {
         NSLog(@"已添加上");
      }       
    
    28.UIView强制赋值图片
    // 跨框架赋值需要进行桥接
    self.view.layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"123"].CGImage); 
    
    29.判断类里面是否有实现某个方法
    //判断wearNeat方法有没有在Student中实现了
    if([stu respondsToSelector:@selector(wearNeat)]){
          [stu wearNeat];
      }                    
    
    30.给有问题的代码打警告
    #warning 代码过几天在补充
    

    相关文章

      网友评论

        本文标题:iOS-OC常见技术点整理

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