iOS 疑难杂症

iOS 开发学习中,碰到的各种奇葩问题或一些知识点的总结,总有一款适合你... ...

1、UITextField统计字数
- (void)textFieldDidChange:(UITextField *)textField
{
    NSInteger kMaxLength = 20;//设置最大字数限制
    NSString *toBeString = textField.text;
    NSString *lang = [textField.textInputMode primaryLanguage]; // 键盘输入模式
    if ([lang isEqualToString:@"zh-Hans"]) { // 简体中文输入,包括简体拼音,健体五笔,简体手写
        UITextRange *selectedRange = [textField markedTextRange];
        //获取高亮部分
        UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];
        // 没有高亮选择的字,则对已输入的文字进行字数统计和限制
        if (!position) {
            if (toBeString.length > kMaxLength) {
                textField.text = [toBeString substringToIndex:kMaxLength];
            }
            //自己的控件赋值
            _labTitleLength.text = [NSString stringWithFormat:@"%zd/20",textField.text.length];
            _mFeedback.title = textField.text;
        }
        // 有高亮选择的字符串,则暂不对文字进行统计和限制
        else{
            
        }
    }
    // 中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
    else{
        if (toBeString.length > kMaxLength) {
            textField.text = [toBeString substringToIndex:kMaxLength];
            [textField resignFirstResponder];
        }
        //自己的控件赋值
        _labTitleLength.text = [NSString stringWithFormat:@"%zd/20",textField.text.length];
        _mFeedback.title = textField.text;
    } 
}
2、跳转到任意ViewController
UIViewController *controller = nil;
for (UIViewController *vc in self.navigationController.viewControllers)
{
     AMLog(@"self.nav %@",self.navigationController.viewControllers);
     if ([vc isKindOfClass:[MyCustomViewController class]]) {
            controller = (UIViewController *)vc;
            break;
     }
}
[self.navigationController pushViewController: controller animated:YES];
3、 becomeFirstResponder not working in iOS 8 Later
[UITextField performSelector:@selector(becomeFirstResponder:) withObject:nil afterDelay:0];
4、 处理UIPanGestureRecognizer与UIScrollView手势冲突问题
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
     [otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];
     return YES;
}
5、获取图片扩展名的正确姿势
//通过图片Data数据第一个字节 来获取图片扩展名
- (NSString *)contentTypeForImageData:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return @"jpeg";
        case 0x89:
            return @"png";     
        case 0x47:
            return @"gif";        
        case 0x49:   
        case 0x4D:
            return @"tiff";        
        case 0x52:  
            if ([data length] < 12) {
                return nil;
            }
            NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                return @"webp";
            }
            return nil;
    }
    return nil;
}
6、设置图片圆角

*不推荐的方式,原因 图层 使用过量会有卡顿现象。

self.iconImage.layer.cornerRadius = 20;
self.iconImage.layer.masksToBounds = YES;

*推荐的方式,用 绘图 来做。

/** 设置圆形图片 */
- (UIImage *)cutCircleImage {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
    // 获取上下文
    CGContextRef ctr = UIGraphicsGetCurrentContext();
    // 设置圆形
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGContextAddEllipseInRect(ctr, rect);
    // 裁剪
    CGContextClip(ctr);
    // 将图片画上去
    [self drawInRect:rect];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

注:如果屏幕上有很多需要绘制的圆角(如日历),建议用第二种方式,如果是不多的正常显示图标,大胆放心的使用第一种方式,亲测过GUP不会卡,能达到最顺滑的60值。

7、## 符号在宏里面的使用
#define LRWeakSelf(type)  __weak typeof(type) weak##type = type;

##是连接的作用, 即当使用上面的宏会把weak与输入的type值连接起来如下图:

iOS 疑难杂症_第1张图片
图 1.png
8、在Block中一起使用 weakSelf 与 strongSelf 的含义

先定义两个宏:

#define LRWeakSelf(type)  __weak typeof(type) weak##type = type;
#define LRStrongSelf(type)  __strong typeof(type) type = weak##type;

我们创建一个shop并且在shop.myBlock代码块中使用弱引用LRWeakSelf(shop);

LRShop *shop = [[LRShop alloc]init];
shop.string = @"welcome to our company";
//弱引用
LRWeakSelf(shop);
shop.myBlock = ^{
    NSLog(@"%@",weakshop.string);
};
shop.myBlock();

LRWeakSelf(shop);LRStrongSelf(shop);一起使用

LRShop *shop = [[LRShop alloc]init];
shop.string = @"welcome to our company";
//弱引用
LRWeakSelf(shop);
shop.myBlock = ^{
     //强引用
     LRStrongSelf(shop)
     NSLog(@"%@",shop.string);
 };
 shop.myBlock();

这2个打印结果都是shop.string有值并且shop也销毁了, 看起来是没什么区别。

但是仅仅使用LRWeakSelf(shop);并且在myBlock中增加一个延迟3秒在输出就会出现问题, 虽然对象销毁了, 输出的值却是null;

//弱引用
 LRWeakSelf(shop);
 shop.myBlock = ^{dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",weakshop.string);  });
 };
 shop.myBlock();

如果LRWeakSelf(shop);LRStrongSelf(shop);一起使用输出的shop.string有值,对象也销毁了;

//弱引用
 LRWeakSelf(shop);
 shop.myBlock = ^{
        //强引用
        LRStrongSelf(shop)
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"%@",shop.string);
        });
 };
 shop.myBlock();

通过上面一堆的解释, 我们明显发现LRWeakSelf(shop);LRStrongSelf(shop);一起使用的好处, 不但能打印出我想要的值,而且也不会造成循环引用 , 在开发中这两个方法可以根据实际情况进行使用!

9、UITextField 监听中文文本变化
[textField addTarget:self action:@selector(textEditingChanged) forControlEvents:UIControlEventEditingChanged];
10、恢复系统侧滑返回功能
//设置代理
self.interactivePopGestureRecognizer.delegate = self;
#pragma mark - 
//实现代理方法:return YES :手势有效, NO :手势无效
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    //当导航控制器的子控制器个数 大于1 手势才有效
    return self.childViewControllers.count > 1;
}
11、打电话问题

iOS应用内打电话的时候,蜂窝数据流量会关闭,返回应用的时候,如果数据流量恢复不及时,很可能引起App的问题,引起重视。

12、路由响应链方法进行传值
// 核心代码
#import "UIResponder+Router.h"
@implementation UIResponder (Router)
- (void)routerWithEventName:(NSString *)eventName userInfo:(NSDictionary *)userInfo {
    if (self.nextResponder) {
         [[self nextResponder] routerWithEventName:eventName userInfo:userInfo];
    }
}
@end
13、数组和字典相关

1、数组为空时:

NSArray *array = [[NSArray alloc] init];
[array lastObject];//不崩溃
[array objectAtIndex:0];//崩溃
[array objectAtIndex:-1];//不崩溃,值为nil

2、objectForKey 与 valueForKey 在 NSDictionary 中的差异:

解释:
* objectForKey: 返回指定 key 的 value,若没有这个 key 返回 nil.
* valueForKey:一般来说 key 可以是任意字符串组合,如果 key 不是以 @ 符号开头,这时候 valueForKey: 等同于 objectForKey:,如果是以 @ 开头,去掉 key 里的 @ 然后用剩下部分作为 key 执行 [super valueForKey:]。
代码:
NSDictionary *dict = [NSDictionary dictionaryWithObject:@"theValue" forKey:@"@theKey"];// 注意这个 key 是以 @ 开头
NSString *value1 = [dict objectForKey:@"@theKey"];//取值正确,theValue
NSString *value2 = [dict valueForKey:@"@theKey"];//崩溃
结论:
建议在 NSDictionary 下只用 objectForKey: 来取值。
14、UITextField输入一个字符时,按钮高亮显示
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSUInteger length = textField.text.length - range.length + string.length;
    if (length > 0) {
        _btnVerify.enabled = YES;
        [_btnVerify ak_setImageBackgroundColor:kACColorBlue forStatus:UIControlStateNormal];
    } else {
        _btnVerify.enabled = NO;
        [_btnVerify ak_setImageBackgroundColor:kACColorGray3 forStatus:UIControlStateNormal];
    }
    return YES;
}
15、应用进入后台,重新启动应用,私有方法,不能过审App Store
//退到后台
[[UIApplication sharedApplication] performSelector:@selector(suspend)];
//延迟个时长,再执行重启,不然会崩溃
[NSThread sleepForTimeInterval:0.3];
//重新启动应用
exit(0);
16、UITableView的plain样式下,取消区头停滞效果
-(void)scrollViewDidScroll:(UIScrollView*)scrollView   
{  
   CGFloat sectionHeaderHeight = sectionHeadView.height;  
   if(scrollView.contentOffset.y <= sectionHeaderHeight && scrollView.contentOffset.y >= 0){  
      scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);  
   } else if(scrollView.contentOffset.y >= sectionHeaderHeight){  
      scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);  
   }  
}
17、两种方法删除NSUserDefaults所有记录
//方法一
NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
 
//方法二
- (void)resetDefaults
{
    NSUserDefaults * defs = [NSUserDefaults standardUserDefaults];
    NSDictionary * dict = [defs dictionaryRepresentation];
    for (id key in dict)
    {
        [defs removeObjectForKey:key];
    }
    [defs synchronize];
}
18、禁止锁屏
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
19、Xcode调试不显示内存占用
editSCheme  里面有个选项叫叫做 enable zoombie Objects  取消选中
20、字符串按多个符号分割
NSString *str = @"abc,xyz.uvw";
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:@",."];
NSLog(@"%@",[str componentsSeparatedByCharactersInSet:set]);
21、获取汉字的拼音
+ (NSString *)transform:(NSString *)chinese
{    
    //将NSString装换成NSMutableString 
    NSMutableString *pinyin = [chinese mutableCopy];    
    //将汉字转换为拼音(带音标)    
    CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformMandarinLatin, NO);    
    NSLog(@"%@", pinyin);    
    //去掉拼音的音标    
    CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformStripCombiningMarks, NO);    
    NSLog(@"%@", pinyin);    
    //返回最近结果    
    return pinyin;
 }
22、判断view是不是指定视图的子视图
BOOL isSubView = [textView isDescendantOfView:self.view];
23、NSArray 快速求总和 最大值 最小值 和 平均值
NSArray *array = [NSArray arrayWithObjects:@"2.0", @"2.3", @"3.0", @"4.0", @"10", nil];
CGFloat sum = [[array valueForKeyPath:@"@sum.floatValue"] floatValue];
CGFloat avg = [[array valueForKeyPath:@"@avg.floatValue"] floatValue];
CGFloat max =[[array valueForKeyPath:@"@max.floatValue"] floatValue];
CGFloat min =[[array valueForKeyPath:@"@min.floatValue"] floatValue];
24、获取一个类的所有子类
+ (NSArray *)allSubclasses
{
    Class myClass = [self class];
    NSMutableArray *mySubclasses = [NSMutableArray array];
    unsigned int numOfClasses;
    Class *classes = objc_copyClassList(&numOfClasses;);
    for (unsigned int ci == 0; ci < numOfClasses; ci++)
    {
        Class superClass = classes[ci];
        do{
            superClass = class_getSuperclass(superClass);
        } while (superClass && superClass != myClass);
 
        if (superClass)
        {
            [mySubclasses addObject: classes[ci]];
        }
    }
    free(classes);
    return mySubclasses;
}
25、取消UICollectionView的隐式动画
//方法一
[UIView performWithoutAnimation:^{
    [collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]];
}];
 
//方法二
[UIView animateWithDuration:0 animations:^{
    [collectionView performBatchUpdates:^{
        [collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]];
    } completion:nil];
}];
 
//方法三
[UIView setAnimationsEnabled:NO];
[self.trackPanel performBatchUpdates:^{
    [collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:index inSection:0]]];
} completion:^(BOOL finished) {
    [UIView setAnimationsEnabled:YES];
}];
26、UIView设置部分圆角
CGRect rect = view.bounds;
CGSize radio = CGSizeMake(30, 30);//圆角尺寸
UIRectCorner corner = UIRectCornerTopLeft|UIRectCornerTopRight;//这只圆角位置
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corner cornerRadii:radio];
CAShapeLayer *masklayer = [[CAShapeLayer alloc]init];//创建shapelayer
masklayer.frame = view.bounds;
masklayer.path = path.CGPath;//设置路径
view.layer.mask = masklayer;
27、获取私有属性和成员变量
#import 
举例 1、
//获取私有属性 比如设置UIDatePicker的字体颜色
- (void)setTextColor
{
    //获取所有的属性,去查看有没有对应的属性
    unsigned int count = 0;
    objc_property_t *propertys = class_copyPropertyList([UIDatePicker class], &count);
    for(int i = 0;i ( count;i ++)
    {
        //获得每一个属性
        objc_property_t property = propertys[i];
        //获得属性对应的nsstring
        NSString *propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        //输出打印看对应的属性
        NSLog(@"propertyname = %@",propertyName);
        if ([propertyName isEqualToString:@"textColor"])
        {
            [datePicker setValue:[UIColor whiteColor] forKey:propertyName];
        }
    }
}

举例 2、
//获得成员变量 比如修改UIAlertAction的按钮字体颜色
- (void)setTextColor
{
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([UIAlertAction class], &count);
    for(int i =0;i ( count;i ++)
    {
        Ivar ivar = ivars[i];
        NSString *ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding];
        NSLog(@"uialertion.ivarName = %@",ivarName);
        if ([ivarName isEqualToString:@"_titleTextColor"])
        {
            [alertOk setValue:[UIColor blueColor] forKey:@"titleTextColor"];
            [alertCancel setValue:[UIColor purpleColor] forKey:@"titleTextColor"];
        }
    }
}
28、应用内打开系统设置界面
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
29、数字的格式化
//通过NSNumberFormatter,同样可以设置NSNumber输出的格式。例如如下代码:
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle = NSNumberFormatterDecimalStyle;
NSString *string = [formatter stringFromNumber:[NSNumber numberWithInt:123456789]];
NSLog(@"Formatted number string:%@",string);
//输出结果为:[1223:403] Formatted number string:123,456,789
 
//其中NSNumberFormatter类有个属性numberStyle,它是一个枚举型,设置不同的值可以输出不同的数字格式。该枚举包括:
typedef NS_ENUM(NSUInteger, NSNumberFormatterStyle) {
    NSNumberFormatterNoStyle = kCFNumberFormatterNoStyle,
    NSNumberFormatterDecimalStyle = kCFNumberFormatterDecimalStyle,
    NSNumberFormatterCurrencyStyle = kCFNumberFormatterCurrencyStyle,
    NSNumberFormatterPercentStyle = kCFNumberFormatterPercentStyle,
    NSNumberFormatterScientificStyle = kCFNumberFormatterScientificStyle,
    NSNumberFormatterSpellOutStyle = kCFNumberFormatterSpellOutStyle
};
//各个枚举对应输出数字格式的效果如下:其中第三项和最后一项的输出会根据系统设置的语言区域的不同而不同。
[1243:403] Formatted number string:123456789
[1243:403] Formatted number string:123,456,789
[1243:403] Formatted number string:¥123,456,789.00
[1243:403] Formatted number string:-539,222,988%
[1243:403] Formatted number string:1.23456789E8
[1243:403] Formatted number string:一亿二千三百四十五万六千七百八十九
30、ceil()和floor()
ceil() 功能:返回大于或者等于指定表达式的最小整数。
floor() 功能:返回小于或者等于指定表达式的最大整数。
31、摇一摇功能
1、打开摇一摇功能
[UIApplication sharedApplication].applicationSupportsShakeToEdit = YES;
2、让需要摇动的控制器成为第一响应者
[self becomeFirstResponder];
3、实现以下方法
 
// 开始摇动
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
// 取消摇动
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
// 摇动结束
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
32、让label的文字内容显示在左上/右上/左下/右下/中心顶/中心底部
自定义UILabel
// 重写label的textRectForBounds方法
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines {
    CGRect rect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
    switch (self.textAlignmentType) {
        case WZBTextAlignmentTypeLeftTop: {
            rect.origin = bounds.origin;
        }
            break;
        case WZBTextAlignmentTypeRightTop: {
            rect.origin = CGPointMake(CGRectGetMaxX(bounds) - rect.size.width, bounds.origin.y);
        }
            break;
        case WZBTextAlignmentTypeLeftBottom: {
            rect.origin = CGPointMake(bounds.origin.x, CGRectGetMaxY(bounds) - rect.size.height);
        }
            break;
        case WZBTextAlignmentTypeRightBottom: {
            rect.origin = CGPointMake(CGRectGetMaxX(bounds) - rect.size.width, CGRectGetMaxY(bounds) - rect.size.height);
        }
            break;
        case WZBTextAlignmentTypeTopCenter: {
            rect.origin = CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(rect)) / 2, CGRectGetMaxY(bounds) - rect.origin.y);
        }
            break;
        case WZBTextAlignmentTypeBottomCenter: {
            rect.origin = CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(rect)) / 2, CGRectGetMaxY(bounds) - CGRectGetMaxY(bounds) - rect.size.height);
        }
            break;
        case WZBTextAlignmentTypeLeft: {
            rect.origin = CGPointMake(0, rect.origin.y);
        }
            break;
        case WZBTextAlignmentTypeRight: {
            rect.origin = CGPointMake(rect.origin.x, 0);
        }
            break;
        case WZBTextAlignmentTypeCenter: {
            rect.origin = CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(rect)) / 2, (CGRectGetHeight(bounds) - CGRectGetHeight(rect)) / 2);
        }
            break;
        default:
            break;
    }
    return rect;
}
- (void)drawTextInRect:(CGRect)rect {
    CGRect textRect = [self textRectForBounds:rect limitedToNumberOfLines:self.numberOfLines];
    [super drawTextInRect:textRect];
}
33、isKindOfClass和isMemberOfClass的区别
isKindOfClass可以判断某个对象是否属于某个类,或者这个类的子类。
isMemberOfClass更加精准,它只能判断这个对象类型是否为这个类(不能判断子类)
34、将tableView滚动到顶部
[tableView setContentOffset:CGPointZero animated:YES];
或者
[tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
35、在指定的宽度下,让UILabel自动设置最佳font
label.adjustsFontSizeToFitWidth = YES;
36、Cell添加侧滑按钮,iOS 8之后有系统方法可实现
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewRowAction *rowActionSec = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal
                     title:@"复制\n车源ID"
                   handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
                           NSLog(@"复制车源ID");
                        }];
    rowActionSec.backgroundColor = kColorBackground0;
    NSArray *arr = @[rowActionSec];
    return arr;
}

/** 要想改变按钮的样式,可在 cell.m 中重绘 */
- (void)layoutSubviews {
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:NSClassFromString(@"UITableViewCellDeleteConfirmationView")]) {
            
            UIView *shareConfirmationView = subView.subviews[0];
            //颜色
            shareConfirmationView.backgroundColor = kColorBlue1;
            //大小
            CGRect frame = shareConfirmationView.frame;
            frame.origin.y = 10;
            frame.size.height = self.contentView.size.height - frame.origin.y;
            shareConfirmationView.frame = frame;
            
            //改变文字 成为 图片
            for (UIView *shareView in shareConfirmationView.subviews) {
                UIImageView *shareImage = [[UIImageView alloc] init];
                shareImage.contentMode = UIViewContentModeScaleAspectFit;
                shareImage.image = [UIImage imageNamed:share];
                shareImage.frame = CGRectMake(0, 0, shareView.frame.size.width, shareView.frame.size.height);
                [shareView addSubview:shareImage];
            }
        }
    }
}

*******   重中之重  ********
#pragma mark - 编辑cell的代理方法,iOS8必须添加这个方法,iOS9之后不需要,大坑
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
}

注:iOS 11有新方法啦,代替上面代理方法。

37、根据系统时间计算 起始时间
/**
 *  自定义时间类型
 */
typedef NS_ENUM(NSUInteger, CMCustomDateType) {
    /**
     *  不限
     */
    CMCustomDateTypeNone = 0,
    /**
     *  今天
     */
    CMCustomDateTypeToday = 1,
    /**
     *  昨天
     */
    CMCustomDateTypeYesterday = 2,
    /**
     *  本周
     */
    CMCustomDateTypeThisWeek = 3,
    /**
     *  上周
     */
    CMCustomDateTypeLastWeek = 4,
    /**
     *  本月
     */
    CMCustomDateTypeThisMonth = 5,
    /**
     *  上月
     */
    CMCustomDateTypeLastMonth = 6,
    /**
     *  本季
     */
    CMCustomDateTypeThisQuarter = 7,
    /**
     *  上季
     */
    CMCustomDateTypeLastQuarter = 8,
    /**
     *  今年
     */
    CMCustomDateTypeThisYear = 9,
    /**
     *  去年
     */
    CMCustomDateTypeLastYear = 10
};

- (NSDictionary *)getCustomDateBeginAndEndWithType:(CMCustomDateType)type {
    NSDictionary *dict = [NSDictionary dictionary];
    NSDate *newDate = [NSDate date];
    
    double interval = 0;
    NSDate *beginDate = nil;
    NSDate *endDate = nil;
    
    NSCalendar *calendar = [NSCalendar currentCalendar];
    [calendar setFirstWeekday:2];//设定周一为周首日
    
    NSDateComponents *comps = [[NSDateComponents alloc] init];
    
    NSCalendarUnit unit = NSNotFound;
    if (type == CMCustomDateTypeNone) {//不限
        dict = @{@"starttime":@"",@"endtime":@""};
        return dict;
    }else if (type == CMCustomDateTypeToday) {//今天
        unit = NSCalendarUnitDay;
    }else if (type == CMCustomDateTypeYesterday) {//昨天
        unit = NSCalendarUnitDay;
        [comps setDay:-1];
        newDate = [calendar dateByAddingComponents:comps toDate:newDate options:0];
    }else if (type == CMCustomDateTypeThisWeek) {//本周
        unit = NSCalendarUnitWeekOfMonth;
    }else if (type == CMCustomDateTypeLastWeek) {//上周
        unit = NSCalendarUnitWeekOfMonth;
        [comps setWeekOfYear:-1];
        newDate = [calendar dateByAddingComponents:comps toDate:newDate options:0];
    }else if (type == CMCustomDateTypeThisMonth) {//本月
        unit = NSCalendarUnitMonth;
    }else if (type == CMCustomDateTypeLastMonth) {//上月
        unit = NSCalendarUnitMonth;
        [comps setMonth:-1];
        newDate = [calendar dateByAddingComponents:comps toDate:newDate options:0];
    }else if (type == CMCustomDateTypeThisQuarter) {//本季度
        unit = NSCalendarUnitQuarter;
    }else if (type == CMCustomDateTypeLastQuarter) {//上季度
        unit = NSCalendarUnitQuarter;
        [comps setMonth:-3];
        newDate = [calendar dateByAddingComponents:comps toDate:newDate options:0];
    }else if (type == CMCustomDateTypeThisYear) {//今年
        unit = NSCalendarUnitYear;
    }else if (type == CMCustomDateTypeLastYear) {//去年
        unit = NSCalendarUnitYear;
        [comps setYear:-1];
        newDate = [calendar dateByAddingComponents:comps toDate:newDate options:0];
    }
    
    BOOL ok = [calendar rangeOfUnit:unit startDate:&beginDate interval:&interval forDate:newDate];
    //分别修改为 NSDayCalendarUnit NSWeekCalendarUnit NSYearCalendarUnit
    if (ok) {
        endDate = [beginDate dateByAddingTimeInterval:interval-1];
    }else {
        return dict;
    }
    NSDateFormatter *myDateFormatter = [[NSDateFormatter alloc] init];
    [myDateFormatter setDateFormat:@"yyyy-MM-dd"];
    NSString *beginString = [myDateFormatter stringFromDate:beginDate];
    NSString *endString = [myDateFormatter stringFromDate:endDate];
    
    dict = @{@"starttime":beginString,@"endtime":endString};
    return dict;
}
38、动态计算cell高度,超简单方式
// cell中核心代码
- (CGFloat)privateHeightForTableViewCell {
    [self setNeedsLayout];//标记为需要刷新布局,但不立即刷新
    [self layoutIfNeeded];//立即刷新布局
    
    CGFloat rowHeight = 0.0;
    for (UIView *contentView in self.contentView.subviews) {
        if (rowHeight < CGRectGetMaxY(bottomView.frame)) {
                rowHeight = CGRectGetMaxY(bottomView.frame);
        }
    }
    return rowHeight;
}

// View中 或者 ViewController中 tableview获取高度的代理方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    CMDealerCarSourceCell *cell = (CMDealerCarSourceCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
    return [cell privateHeightForTableView];
}
39、UIView的setNeedsLayout, layoutIfNeeded 和 layoutSubviews 方法之间的关系解释
//刷新子对象布局

-layoutSubviews 方法:这个方法,默认没有做任何事情,需要子类进行重写。
-setNeedsLayout 方法:标记为需要重新布局,但不会立即刷新,需异步调用layoutIfNeeded刷新布局,但layoutSubviews一定会被调用。
-layoutIfNeeded 方法:如果有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)。

如果要立即刷新,要先调用[view setNeedsLayout],把标记设为需要布局,然后马上调用[view layoutIfNeeded],实现布局。

在视图第一次显示之前,标记总是“需要刷新”的,可以直接调用[view layoutIfNeeded]。
40、iOS关键字

idtypedefrestrictdescriptionvolatilesynthesizeconststaticinstancetypecounttypeidtypename

41、谓词筛选
NSPredicate *pre = [NSPredicate predicateWithFormat:@"modelremark == %@",@"销售线索"];
NSArray *arr = [infoModel.rolelist filteredArrayUsingPredicate:pre];
if (arr.count) {
    _authType = SaleCarAuth_Leads;
}

总结:

以上全部亲测,如果各位大侠使用过程中出现问题,可以及时联系作者,更改并学习。

你可能感兴趣的:(iOS 疑难杂症)