项目问题汇总

一、结构体的使用struct

结构体能更加方便的定义好不同的属性,我们使用起来更方便,减少了我们使用中进一步去手动获取数据。

1、定义结构体:

struct TYTCommonResponse {
    NSUInteger code;
    NSString *_Nullable msg;
    id _Nullable data; //上面三个手动拆分的数据    
    id _Nullable rowData; // 接口返回原数据
};
声明结构体:
typedef struct TYTCommonResponse TYTCommonResponse;

12、使用结构体回传数据

比如我们封装好网络请求,response的数据需要进一步解析。

- (void)responseStructWithURLString:(NSString *)path onSuccess:(nullable void (^)(struct TYTCommonResponse))success responseObject:(id _Nullable)responseObject
{
    TYTCommonResponse resultObj;
    resultObj.code = [responseObject[@"code"] integerValue];
    resultObj.msg = responseObject[@"msg"];
    resultObj.data = responseObject[@"data"];    
    resultObj.rowData = responseObject;
    TYTLog(@"返回数据(%@):%@", path, [NSString stringWithFormat:@"\ncode: %zd\nmsg: %@\nrowData: %@", resultObj.code, resultObj.msg, resultObj.rowData]);
    
    [TYTResultCodeHandler handleMessageWithCode:resultObj.code data:responseObject];    
    if (success) {
        success(resultObj);
    }
}

二、WKWebView中的Cookie

Cookie是我们日常浏览的网页页面为了识别具体的用户身份,而在request Header加带的一种数据。有了这个数据,你要浏览的的网页就知道你是哪个用户。
举个例子:如果浏览网站的时候没有Cookie或者Cookie失效了,那么就会出现这种情况。你隔了好多天访问微博网页,点击的标签明明之前保存的是你登录之后的微博首页,可以直接看到你的好友动态。但是现在它却给你跳转了登录页面先要你登录。就是因为你Cookie失效导致的。微博没办法判断你是否是有效用户了。
另外,我们需要特别注意,在页面跳转的时候,网站有时候会自己在request Header中加入一些Cookie,也作为身份校验的一部分。
Cookie可以由native端设置也可以由服务端来设置。
客户端想要打印出webView中的Cookie,就有四个地方可选了:

1、native端设置Cookie的时候
2、获取request Header
3、获取document.cookie的内容
4、获取response header中的set-cookie

WKWebView中设置Cookie的方案:


Cookie版本适配方案

适配iOS11.0~iOS11.2
苹果在iOS11.0推出了WKHTTPCookieStore,这个类对WKWebView的效果和NSHttpCookieStorage对UIWebView的效果一样,并且也是零延迟。在请求发起的时候,我们只需要将Cookie设置到WKHTTPCookieStore就可以了。

// 1. 设置Cookie
WKWebsiteDataStore *store = [WKWebsiteDataStore defaultDataStore];
[store.httpCookieStore setCookie:cookie completionHandler:^{
NSLog(@“cookie添加成功”);
}];

// 2. 加载请求
[self.wkwebView loadRequest: request];

适配iOS11.3
WKHTTPCookieStore第一次设置Cookie之后,发起请求,Cookie不能同步到request Header中。此时,webView重新请求页面,WKHTTPCookieStore的作用恢复正常,之后请求其他的webView也不会出现Cookie丢失的问题。 总结就是在iOS11.3中,WKHTTPCookieStore设置Cookie之后,第一次发起请求Cookie会丢失,第二次及以后的请求的Cookie没有问题。

解决方式是,我们在执行loadRequest之前主动设置一次Cookie。我这里是在didFinishLaunchOption:中设置的。设置完之后,就没有问题了,注意,他是单利奥。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{
   WKWebsiteDataStore *store = [WKWebsiteDataStore defaultDataStore];
    [store.httpCookieStore setCookie:cookie completionHandler:^{
        NSLog(@“cookie添加成功”);
    }];
}

WKWebView如何加Cookie系列

三、Bundle 和 xcassets 的主要区别

简述:

1、工程中所有使用 Asset Catalog 管理的图片(在 .xcassets 文件夹下),最终输出的时候,都会被压缩到 Assets.car 内。
2、反之,不在 Assets.car 内的,我们将它统一归类为 Bundle 管理的。

Bundle 和 xcassets 的主要区别有:

1、xcassets 里面的图片,只能通过 imageNamed 加载。Bundle 还可以通过 imageWithContentsOfFile 等方式。
2、xcassets 里的 2x 和 3x,会根据具体设备分发,不会同时包含。而 Bundle 会都包含。(App Slicing)
3、xcassets 内,可以对图片进行 Slicing,即裁剪和拉伸。Bundle 不支持。所以,Bundle会使包的体积变大。
4、Bundle 内支持多语言,xcassets 不支持。
xcassets使用 imageNamed 创建的 UIImage,会立即被加入到 NSCache 中(解码后的 Image Buffer),直到收到内存警告的时候,才会释放不在使用的 UIImage。
而 Bundle的imageWithContentsOfFile方式,它每次都会重新申请内存,相同图片不会缓存。
所以,xcassets 内的图片,加载后会产生缓存,Bundle则不会,所以在开发中,常用的,较小的图,应该放在 xcassets 内管理。而大图应该放在 Bundle 内管理。

三、宏定义调用方法

以block的方式调用,每次换行都要添加\,否则报错。

#pragma mark - 适配ios11 和iPhone X
#define isiPhoneX \
({BOOL isPhoneX = NO;\
if (@available(iOS 11.0, *)) {\
isPhoneX = [[UIApplication sharedApplication] delegate].window.safeAreaInsets.bottom > 0.0;\
}\
(isPhoneX);})

// 判断是否是iPhone 5
#define  isiPhone5 Screen_Width == 320
// iPhoneX的状态栏的高度
//#define  TYT_StatusBarHeight      (isiPhoneX ? 44.f : 20.f)
#define  TYT_StatusBarHeight \
^(){\
 if (@available(iOS 13.0, *)) {\
     UIStatusBarManager *statusBarManager = [[[UIApplication sharedApplication] windows] objectAtIndex:0].windowScene.statusBarManager;\
     return statusBarManager.statusBarFrame.size.height;\
 }else{\
     return [[UIApplication sharedApplication] statusBarFrame].size.height;\
 }\
}()

// iPhoneX的导航栏的高度
#define  TYT_NavBarHeight \
^(){\
 if (@available(iOS 13.0, *)) {\
     UIStatusBarManager *statusBarManager = [[[UIApplication sharedApplication] windows] objectAtIndex:0].windowScene.statusBarManager;\
     return statusBarManager.statusBarFrame.size.height+44;\
 }else{\
     return [[UIApplication sharedApplication] statusBarFrame].size.height+44;\
 }\
}()

四、Block作为返回值使用

__nullable:可以为空
这里遇到一个崩溃,设置为nil,打断点发现completion是null,就是但是completion没有判空,导致崩溃,加了判空就可以了。

[self startAreaSelViewAnimation:nil];
#pragma mark -- 开始动画
- (void)startAreaSelViewAnimation:(void (^ __nullable)(BOOL finished))completion{
    [UIView animateWithDuration:0.25 animations:^{
        self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
        _backGroundView.frame = CGRectMake(0, _backGroundView.frame.origin.y, Screen_Width, _newBgHeight);//locationView.y+locationView.height
    } completion:^(BOOL finished) {
        if (completion != nil) {
            completion(finished);
        }
    }];
}

五、Xcode 14.3升级后运行报错

模拟器:

ld: file not found: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a
clang: error: linker command failed with exit code 1 (use -v to see invocation)

真机:

ld: file not found: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a
clang: error: linker command failed with exit code 1 (use -v to see invocation)

由于Xcode 14.3版本移除了ARC相关的库,从而导致一些默认部署目标是iOS 8版本的第三方库出现报错。只要最低部署目标不低于iOS 9版本,运行项目时就不会去链接ARC相关的库,也就不会出现找不到库的报错。

解决方法

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' 
    end
  end
end

11.0是你支持的最低版本,并不是固定的。
解决方案链接

六、自定义AlertView的文字颜色

Title使用富文本。
alterView使用KVC设置颜色。

- (void)createWaitActivateAlertView{
    NSString *message = @"您的企业账户未完成激活,不能发”专票“货源,请尽快激活。激活之前,您只能发布不开票或普票货源。";
    NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:message];
    [attrStr addAttribute:NSForegroundColorAttributeName
                    value:kUIColorFromRGB(0x666666)
                    range:NSMakeRange(0, 28)];
    [attrStr addAttribute:NSForegroundColorAttributeName
                    value:kUIColorFromRGB(0xFE9D09)
                    range:NSMakeRange(attrStr.length-19, 19)];
    [attrStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:NSMakeRange(0, attrStr.length)];
    
    UIAlertController *alterView = [UIAlertController alertControllerWithTitle:@"您的企业账户待激活" message:nil preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *cancle = [UIAlertAction actionWithTitle:@"暂不激活" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    }];
    [alterView setValue:attrStr forKey:@"attributedMessage"];
    [cancle setValue:kUIColorFromRGB(0x999999) forKey:@"titleTextColor"];
    UIAlertAction *sure = [UIAlertAction actionWithTitle:@"去激活" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    [sure setValue:kUIColorFromRGB(0x3194EF) forKey:@"titleTextColor"];
    [alterView addAction:cancle];
    [alterView addAction:sure];
    [self presentViewController:alterView animated:YES completion:nil];
}

七、限定键盘输入的内容

TextField只能输入字母和数字+字数限制。
传送门

1、设置键盘样式

self.textField.keyboardType = UIKeyboardTypeASCIICapable;

2、设置宏条件

#define NUM @"0123456789"
#define ALPHA @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
#define ALPHANUM @"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

3、textFieldDelegate代理方法

// 只能输入字母和数字
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ALPHANUM] invertedSet];
    NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
    return [string isEqualToString:filtered];
}
// 小写字母转大写字母
- (void)textFieldDidEndEditing:(UITextField *)textField {
    textField.text = [textField.text uppercaseString];
}

八、组件化block传参

需求一个组件调用另一个组件,需要获取返回的参数,有两种方式,一个是delegate,另一个就是block。

1、delegate

通过设置代理,使用responseSelect的方式直接调用方法,方法返回数据之后,使用代理回传参数。调用中CTM的时候不需要在调用VC中声明代理。

1.1 中间件方法
- (UIViewController *)Main_Car_complaintShowBigImagesViewControllerWithDelegate:(id)delegate dataArray:(NSArray *)dataArray index:(NSInteger)index isHidden:(BOOL)isHidden {
    NSMutableDictionary *params = @{}.mutableCopy;
    if (delegate) {
        params[@"delegate"] = delegate;
    }    
    params[@"index"] = @(index);
    return [self performTarget:MainApp_Car_TargetName action:@"complaintShowBigImagesViewController" params:params shouldCacheTarget:NO];
}
1.2 组件中被调用的事件
- (UIViewController *)Action_complaintShowBigImagesViewController:(NSDictionary *)params {
    id data = params[@"data_array"];
    if (![data isKindOfClass:[NSArray class]]) {
        return nil;
    }
    NSArray *images = (NSArray *)data;
    
    TYTComplaintShowBigImagesViewController *viewImage = [[TYTComplaintShowBigImagesViewController alloc] init];
    viewImage.delegate = params[@"delegate"];
    viewImage.dataArray = [NSMutableArray arrayWithArray:images];
    viewImage.isHidden = [params[@"is_hidden"] boolValue];
    viewImage.currentIndex = [params[@"index"] intValue];
    return viewImage;
}

2、block

2.1 中间件方法:
- (void)Shipment_shipViewControllerExcellentCar:(void(^)(NSDictionary *response,BOOL isExcellentCar))callBack{
    NSMutableDictionary *params = [NSMutableDictionary new];
    if(callBack){
        params = @{
            @"block": callBack
        }.mutableCopy;
    }
    [CT() performTarget:Shipment_TargetName action:@"shipmmentManagerExcellentCar" params:params shouldCacheTarget:NO];
}
2.2 组件内被CTM调用的方法:
- (void)Action_shipmmentManagerExcellentCar:(NSDictionary *)params
{
    TYTShipmmentManager *manager = [[TYTShipmmentManager alloc] init];
    void (^callBack)(NSDictionary *response, BOOL isExcellentCar) = params[@"block"];
    if (callBack) {
        manager.callBack  = callBack;
    }
    [manager queryExcellentCarResult:^(NSDictionary *response, BOOL isExcellentCar) {}];
}
2.3 TYTShipmmentManager网络请求赋值

注意,这里的self.callBack(GlobalBlock)一定要有值,否则会崩溃,所以如果CTM没有调用传参复制的话,我们就需要手动复制。

- (void)queryExcellentCarResult:(TYTGShipmmentManagerBlock)callBack{

    if (self.callBack == nil) {
        self.callBack = callBack;
    }
    callBack = self.callBack;
    [[TYTCommonRequestManager sharedManager] fetchResponseMethod:GET forPlatURLString:@"deposit/queryEquity.action" parameters:@{} success:^(struct TYTCommonResponse response) {
        if(response.code == 200){
            NSDictionary *dataDic = (NSDictionary *)response.data;
            if( [dataDic[@"isJoin"] intValue] == 1 && [dataDic[@"blackStatus"] intValue] == 0 && [dataDic[@"authStatus"] intValue] == 1){
                self.callBack(dataDic, YES);
            }else{
                self.callBack(dataDic, NO);
            }
        }else{
            self.callBack(@{},NO);
        }
    } failure:^(NSError * _Nonnull error) {
        self.callBack(@{},NO);
    }];
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容