日常小知识点iOS进阶

iOS-OC常见技术点整理

2017-10-25  本文已影响25人  Simple_Code
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 代码过几天在补充
上一篇下一篇

猜你喜欢

热点阅读