iOS一些小技巧 | 三

一,UIButton让其文字在图片下方:

[operateBt setTitleEdgeInsets:UIEdgeInsetsMake(operateBt.imageView.frame.size.height+14.0, -operateBt.imageView.frame.size.width, 0.0, 0.0)];
[operateBt setImageEdgeInsets:UIEdgeInsetsMake(0.0, 0.0, 0.0, -operateBt.titleLabel.bounds.size.width)];

二,UIButton用SF符号:

        let image = UIImage(named: "record_def_svg")
        
        var config = UIImage.SymbolConfiguration(font: systemFontWithSize(ScaleSize(152.0)));
        if #available(iOS 15.0, *) {
            config = config.applying(UIImage.SymbolConfiguration(paletteColors: [.white]));
        }else {
            image?.withTintColor(.white, renderingMode: .alwaysOriginal);
        }
        image?.withTintColor(.white, renderingMode: .alwaysTemplate);
        recordButton.setImage(image, for: .normal);
        recordButton.setPreferredSymbolConfiguration(config, forImageIn: .normal);

3,主线程返回一个值:

- (BOOL)isBool {
    __block BOOL result;
    if ([NSThread isMainThread]) {
        return YES;
    } else {
        dispatch_sync(dispatch_get_main_queue(), ^{
            result = YES;
        });
    }
    return result;
}

4,willMoveToSuperview,view的方法,view即将添加到superview或者即将被移除的时候调用,例如:

- (void)willMoveToSuperview:(UIView *)newSuperview
{
    if(newSuperview != nil){
        self.bounds = CGRectMake(0.0, 0.0, self.bounds.size.width, self.collectionViewLayout.collectionViewContentSize.height);
    }
    [super willMoveToSuperview:newSuperview];
}

5,UISearchController取消按钮更改其title:

        searchController.searchBar.showsCancelButton = true;
        if let subFirst = searchController.searchBar.subviews.first,searchController.isActive {
            let searchBarContainerView = subFirst.subviews[1];
            for barSuvViews in searchBarContainerView.subviews {
                if barSuvViews.isKind(of: UIButton.self){
                    let cancelButton: UIButton = barSuvViews as! UIButton;
                    cancelButton.setTitle("取消", for: .normal);
                }
            }
        }

6,URL格式化和反格式化:

//格式化URL
+(NSString *)encodeUrl:(NSString *)sourceURL
{
    if (System_Version_Later(9.0)) {
        return [sourceURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    }else{
        return [sourceURL stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"`#%^{}\"[]|\\<> "].invertedSet];
    }
}

//反格式化ULR
- (NSString *)decodeUrl:(NSString *)codeURL
{
    if (System_Version_Later(9.0)) {
        return [codeURL stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    }else{
        return [codeURL stringByRemovingPercentEncoding];
    }
}

七,deviceToken,NSData类型转NSString。

    NSString *strToken;
    //Xcode11打的包,iOS13获取Token有变化
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 13) {
        if (![deviceToken isKindOfClass:[NSData class]]) {
            //记录获取token失败的描述
            return;
        }
        const unsigned *tokenBytes = (const unsigned *)[deviceToken bytes];
        strToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                              ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                              ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                              ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
    
        NSLog(@"deviceToken1:%@", strToken);
    } else {
        strToken = [NSString
                           stringWithFormat:@"%@",deviceToken];
        strToken = [strToken stringByReplacingOccurrencesOfString:@"<" withString:@""];
        strToken = [strToken stringByReplacingOccurrencesOfString:@">" withString:@""];
        strToken = [strToken stringByReplacingOccurrencesOfString:@" " withString:@""];
        NSLog(@"deviceToken2 is: %@", strToken);
    }

八,OC自定义struct。

struct
Sky_Location {
    CGFloat top;
    CGFloat left;
    CGFloat right;
};
typedef struct CG_BOXABLE Sky_Location Sky_Location;

CG_INLINE Sky_Location
Sky_LocationMake(CGFloat top, CGFloat left, CGFloat right)
{
    Sky_Location location; location.top = top; location.left = left; location.right = right; return location;
}

九,自定义View当中,因为使用了延迟调用,例如:
[self performSelector:@selector(countdown) withObject:nil afterDelay:30.0]而导致dealloc不去执行,可在didMoveToSuperview中取消执行selector,可取消引用从而调用dealloc,如下:

//当view加入或离开superview时,调用此方法
- (void)didMoveToSuperview
{
    NSLog(@"didMoveToSuperview");
    if(nil == self.superview){
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(countdown) object:nil];
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(display) object:nil];
    }
}

十,模拟数组循环;

- (void)foreachWithOperate:(void( ^ _Nullable)(id _Nonnull object,NSInteger idx,bool *stop))operate
{
    for (NSInteger i = 0; i < self.count - 1; i++) {
        bool isStop = NO;
        if(operate) {
            operate(self[i],i,&isStop);
        }
        if(YES == isStop) {
            break;
        }
    }
}

十一,以动画的方式刷新tableview。

[UIView transitionWithView:weakSelf.detatilInfoTabView duration: 0.55f options: UIViewAnimationOptionTransitionFlipFromLeft animations: ^(void){
      [weakSelf.detatilInfoTabView reloadData];
}completion:^(BOOL finished) {
      dispatch_async(dispatch_get_main_queue(), ^{
            [weakSelf addFooterViewByAD];
      });
}];

十二,UITextView加载富文本,其资源文件过大导致卡顿的解决办法。

[NSThread detachNewThreadWithBlock:^{
                //
      NSString *jieShaoDetail = [NSString stringWithFormat:@"<head><style>img{width:%f !important;height:auto}</style></head>%@", (ScreenWidth-ScaleForSize(40.0)*2), detailModel.intro];
      NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:[jieShaoDetail dataUsingEncoding:NSUnicodeStringEncoding] options:@{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
      dispatch_async(dispatch_get_main_queue(), ^{
           weakSelf.jieshaoTextView.attributedText = attributedString;
           [weakSelf.bgScrollView layoutIfNeeded];
           weakSelf.bgScrollView.contentSize = CGSizeMake(0.0, weakSelf.yuYueTextView.bottom + ScaleForSize(40.0) + ScaleForSize(100.0));
      });
}];

十三,addChildViewController子控制器之后,要修改子控制器的frame,需要如下:

//父控制器中:
IMSearchInitPageController *siCtrl = [[IMSearchInitPageController alloc]init];
siCtrl.view.frame = CGRectMake(0.0, naviBarHeight, ScreenWidth, ScreenHeight - naviBarHeight);
[self addChildViewController:siCtrl];
[self.view addSubview:siCtrl.view];
//自控制器中修改self.view的大小,重写loadView方法 - 重写self.view
- (void)loadView
{
    self.view = [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, ScreenWidth, ScreenHeight - navigationBarHeight - 8)];
}

十四,根据父类的宽度进行约束,并且在父类的基础上增加一些数值:

//让其view在父类宽度 * 0.7的基础上,增加navigationDisparityHeight的高度。
[self.coverView mas_makeConstraints:^(MASConstraintMaker *make) {
      (void)make.top.left.right;
           make.height.mas_equalTo(self.mas_width).multipliedBy(0.7).offset(navigationDisparityHeight);
}];

十五,在不知道宽高确切数值的情况下,约束宽高相同。

        [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.mas_equalTo(ScaleForLengthWith2(10.0));
            make.right.bottom.mas_equalTo(-ScaleForLengthWith2(10.0));
            make.width.mas_equalTo(self.imageView.mas_height);
        }];

十六,获取label的高度:

//
CGSize descSize = [self.descLable sizeThatFits:CGSizeMake(ScreenWidth-ScaleForSize(60.0)*2, 0.0)];
//

十七,masonry动画:

//
    [cateUnfoldView layoutIfNeeded];
    //
    [UIView animateWithDuration:0.2 animations:^{
        [cateUnfoldView.cateListView mas_updateConstraints:^(MASConstraintMaker *make) {
            make.height.mas_equalTo(datas.count*ScaleForSize(70.0));
        }];
        [cateUnfoldView layoutIfNeeded];
    }];
//

十八,UIImage图片翻转;因拍照时,可能导致UIImage90度翻转,需要进行判断且翻转,然后上传到后台使用:

//
//
UIImage *uploadImage = xxx;
if(uploadImage.imageOrientation == UIImageOrientationRight){
   UIImage *realImage = [UIImage imageWithCGImage:backImage.image.CGImage scale:backImage.image.scale orientation:UIImageOrientationLeftMirrored];
}
if(uploadImage.imageOrientation == UIImageOrientationLeft){
   UIImage *realImage = [UIImage imageWithCGImage:backImage.image.CGImage scale:backImage.image.scale orientation:UIImageOrientationRightMirrored];
}
//realImage为最终图片
//
//

十九,OC中泛型的使用场景:

//
//
#import <Foundation/Foundation.h>

@interface GenericContainer<ObjectType> : NSObject
// 存储泛型数据
@property (nonatomic, strong) NSMutableArray<ObjectType> *items;

// 添加元素到容器
- (void)addItem:(ObjectType)item;

// 获取容器中指定索引的元素
- (ObjectType)itemAtIndex:(NSUInteger)index;

// 获取容器中的元素个数
- (NSUInteger)count;

// 清空容器
- (void)clear;

@end
//
//

二十,weak对象,解决循环引用问题。

//
//
MQChatViewController *chatCtrl = [chatViewManager pushMQChatViewControllerInViewController:controller];
//跳转到商品详情,这里解决循环引用
__weak typeof(chatCtrl) weakChatVc = chatCtrl;
[chatViewManager didTapProductCard:^(NSString *productUrl) {
    //doing - weakChatVc
}];
//
//

二十一,获取UIImage的格式类型。

//
//
- (NSString *)imageFormatForImageData:(NSData *)imageData {
    
    NSString *formatString = @"Unknown";
    if (!imageData) {
        return formatString;
    }
    
    uint8_t c;
    [imageData getBytes:&c length:1];
    
    switch (c) {
        case 0xFF:
            formatString = @"JPEG";
            break;
        case 0x89:
            formatString = @"PNG";
            break;
        case 0x47:
            formatString = @"GIF";
            break;
        case 0x49:
        case 0x4D:
            formatString = @"TIFF";
            break;
        case 0x52: {
            if (imageData.length >= 12) {
                //RIFF....WEBP
                NSString *testString = [[NSString alloc] initWithData:[imageData subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
                if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                    formatString = @"WEBP";
                }
            }
            break;
        }
        case 0x00: {
            if (imageData.length >= 12) {
                //....ftypheic ....ftypheix ....ftyphevc ....ftyphevx
                NSString *testString = [[NSString alloc] initWithData:[imageData subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding];
                if ([testString isEqualToString:@"ftypheic"]
                    || [testString isEqualToString:@"ftypheix"]
                    || [testString isEqualToString:@"ftyphevc"]
                    || [testString isEqualToString:@"ftyphevx"]) {
                    formatString = @"HEIC";
                }
                //....ftypmif1 ....ftypmsf1
                if ([testString isEqualToString:@"ftypmif1"] || [testString isEqualToString:@"ftypmsf1"]) {
                    formatString = @"HEIF";
                }
            }
            break;
        }
        case 0x25: {
            if (imageData.length >= 4) {
                //%PDF
                NSString *testString = [[NSString alloc] initWithData:[imageData subdataWithRange:NSMakeRange(1, 3)] encoding:NSASCIIStringEncoding];
                if ([testString isEqualToString:@"PDF"]) {
                    formatString = @"PDF";
                }
            }
            break;
        }
        case 0x3C: {
            // Check end with SVG tag
            if ([imageData rangeOfData:[@"</svg>" dataUsingEncoding:NSUTF8StringEncoding] options:NSDataSearchBackwards range: NSMakeRange(imageData.length - MIN(100, imageData.length), MIN(100, imageData.length))].location != NSNotFound) {
                formatString = @"SVG";
            }
            break;
        }
        default:
            formatString = @"Unknown";
    }
    return formatString;
}
//
//

使用1,bundle中的图片:
NSString *imageURL = [[NSBundle mainBundle]pathForResource:@"121212" ofType:@"webp"];
NSData *imageData = [NSData dataWithContentsOfFile:imageURL];
NSString *format = [self imageFormatForImageData:imageData];
NSLog(@"%@",format);
使用2,图片选择器中的图片:
NSString *url = [info objectForKey:UIImagePickerControllerImageURL];
NSData *imageData = [NSData dataWithContentsOfFile:url];
NSString *format = [self imageFormatForImageData:imageData];
//
//

Leave a Reply

Required fields are marked *