可变字符串的拼接
如图这段code 报错
原来是我声明属性的时候
@property(nonatomic,copy)NSMutableString * mutableString;
属性是没有mutableCopy的 所以copy出来的其实是一个不可变字符串 所以报错
解决方案很简单 两种
1.简单直接了当
2.直接了当简单
WKWebView与JS的一些简单交互
js调用OC
1.初始化webView的时候 添加处理脚本
2.去代理方法中接收js传过来的参数
#pragma mark - WKScriptMessageHandler
//JS调OC----->OC里调用JS的方法 既能把JS的方法改掉 又能把JS的参数传递过来
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"showName"]||[message.name isEqualToString:@"showName_t"]) {
LDLog(@"%@",message.body);
}
}
-
- dealloc中删除注册的方法
- (void)dealloc
{
LDLog(@"%s",__func__);
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"showName"];
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"showName_t"];
}
就是这么简单! 就可以实现了js调用OC了
- 注意点是:js那边的方法要写在onLoad里 他们需要这么调用 可能和安卓略有不同
function showName(val){
window.webkit.messageHandlers.showName.postMessage(val) ;
}
- 关于第一点中的WeakScriptMessageDelegate是因为
[userCC addScriptMessageHandler:self name:@"showName"];
直接添加对当前控制器 有强引用 造成控制器无法释放的问题
WeakScriptMessageDelegate的具体实现是:
.h
#import
#import
@interface WeakScriptMessageDelegate : NSObject
@property (nonatomic, weak) id scriptDelegate;
- (instancetype)initWithDelegate:(id)scriptDelegate;
@end
.m
#import "WeakScriptMessageDelegate.h"
@implementation WeakScriptMessageDelegate
- (instancetype)initWithDelegate:(id)scriptDelegate {
self = [super init];
if (self) {
_scriptDelegate = scriptDelegate;
}
return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
[self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
- (void)dealloc
{
LDLog(@"%s",__func__);
}
OC调用JS (OC给js传值)更简单 两句代码 多一行都不带写的
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSString * jsStr = [NSString stringWithFormat:@"and_paperid('%@')",self.model.paper_id];
[webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
LDLog(@"%@",error);
}];
}
这个地方 只要打印出error 99%的情况下是H5的把js没写明白
关于H5的弹窗
如果H5里 想向OC传一些值 验证是他没传过来 还是你没接受到 可以让H5写个alert()验证一把
我们只需实现wkwebView的代理方法即可
验证H5的alert()弹窗 使用80%的场景
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
completionHandler();
}
- Confirm弹窗
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
// DLOG(@"msg = %@ frmae = %@",message,frame);
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}])];
[alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}])];
[self presentViewController:alertController animated:YES completion:nil];
}
- TextInput弹窗
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
completionHandler();
}
- WKWebView的加载进度
UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
progressView.progressTintColor = HWColor(0, 170, 100);
progressView.trackTintColor = [UIColor clearColor];
self.progressView = progressView;
[self.view insertSubview:progressView aboveSubview:_webView];
[progressView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.mas_offset(64);
make.left.and.right.mas_equalTo(self.view);
make.height.mas_equalTo(2);
}];
[_webView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.and.left.and.right.mas_offset(0);
make.bottom.mas_offset(0);
}];
[_webView addObserver:self
forKeyPath:@"estimatedProgress"
options:NSKeyValueObservingOptionNew
context:nil];
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"estimatedProgress"]) {
self.progress = self.webView.estimatedProgress;
}else{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
-(void)setProgress:(CGFloat)progress
{
_progress = progress;
if (self.progressView.alpha == 0) {self.progressView.alpha = 1;}
[self.progressView setProgress:progress animated:YES];
if (progress >= 1) {
[UIView animateWithDuration:0.8 animations:^{
self.progressView.alpha = 0;
} completion:^(BOOL finished) {
self.progressView.progress = 0;
}];
}
}
sessionid的验证
- 登录成功后保存
AFHTTPSessionManager *manager=[AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes=[NSSet setWithObjects:@"application/json", nil];
[manager.requestSerializer setHTTPShouldHandleCookies:NO];
manager.requestSerializer.timeoutInterval=5.0f;
[manager POST:LoginAPI parameters:@{@"user_id":_accountTF.text,@"password":_passwordTF.text} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary * dict) {
if ([[NSString stringWithFormat:@"%@",dict[@"flag"]] isEqualToString:@"1"]) {//登录成功
/**保存session*/
NSHTTPURLResponse* response = (NSHTTPURLResponse* )task.response;
NSString* dataCookie = [NSString stringWithFormat:@"%@",[[response.allHeaderFields[@"Set-Cookie"]componentsSeparatedByString:@";"]objectAtIndex:0]];
LDLog(@"登录成功获取到的sessionid = %@",dataCookie);
if ([dataCookie isEqualToString:@"(null)"] || dataCookie == NULL) {
}else
{
[[NSUserDefaults standardUserDefaults] setObject:dataCookie forKey:@"cookie"];
}
successChangeUI();
}else{
[self errorAlert];
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
LDLog(@"error = %@",error);
[self errorAlert];
}];
- 之后发起的每一个请求 都把sessionid拼接到请求头里
AFHTTPSessionManager *manager=[AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes = [[NSSet alloc]initWithObjects:@"text/html",@"application/json",@"application/xml",@"text/javascript", nil];
manager.requestSerializer.timeoutInterval=5.0f;
/*在请求头中添加cookie*/
NSString* headerCookie = [[NSUserDefaults standardUserDefaults] objectForKey:@"cookie"];
if(headerCookie!=nil&& headerCookie.length>0) {
[manager.requestSerializer setValue:headerCookie forHTTPHeaderField:@"Cookie"];
}
[manager POST:TeacherStatisticsMatchHomeAPI parameters:@{@"class_no":class,@"level_id":self.level_id} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, NSDictionary * dict) {
[MBProgressHUD hideHUD];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[MBProgressHUD hideHUD];
LDLog(@"%@",error);
}];
- 目前不太如人意的地方是 需要自动登录 所以逻辑如下 每次启动先去更新一把session
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
if ([LDUserTool isAutoLogin]) {
UIViewController *emptyView = [[UIViewController alloc] init];
self.window.rootViewController = emptyView;
[self saveSessionid:^{
self.window.rootViewController = [[MtTabBarController alloc]init];
} fail:^{
self.window.rootViewController = [[MtTabBarController alloc]init];
}];
}else{
self.window.rootViewController = [[PlatformSelectController alloc]init];
}
[self.window makeKeyAndVisible];
[self monitorNetworkStatus];
return YES;
}
让collectionView的Frame由数据源决定
在网络请求成功的回调里
[self.view layoutIfNeeded];
_collectionView.xmg_height = _collectionView.contentSize.height;
隐藏某个控制器的状态栏
两步
1.在Info.plist中添加View controller-based status bar appearance
2.在需要隐藏的控制器里拷贝上这句代码
- (BOOL)prefersStatusBarHidden
{
return YES;
}
只让项目里的某一个控制器支持横竖屏 其余控制器皆是竖屏
第一步:AppDelegate.m
BOOL isShu = 0;
@implementation AppDelegate
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (isShu == 1) {
return UIInterfaceOrientationMaskAll;
}else{
return (UIInterfaceOrientationMaskPortrait);
}
}
// 支持设备自动旋转
- (BOOL)shouldAutorotate
{
if (isShu == 1) {
return YES;
}
return NO;
}
第二步:支持横竖屏的控制器
extern BOOL isShu;
- (void)viewWillApplear {
isShu = YES;
}
-(void)viewWillDisapplear
{
isShu = NO;
}
两步就OK别的代码不需要写 简单直截了当!
判断横竖屏的方法
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator {
//可根据size参数判断是横还是竖
[_ldPlayView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_offset(0);
make.width.mas_equalTo(size.width);
make.height.mas_equalTo(size.width * 9 / 16);
make.left.mas_offset(0);
}];
}
点击按钮 切换横竖屏
_ldPlayView.crossScreen = ^(BOOL isCross) {
if (isCross) {
NSNumber *orientation = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
//如果当前设备不是横屏
if ([UIDevice currentDevice].orientation!=[orientation integerValue]) {
[[UIDevice currentDevice] setValue:orientation forKey:@"orientation"];
}
}else{
NSNumber *orientation = [NSNumber numberWithInt:UIDeviceOrientationPortrait];
if ([UIDevice currentDevice].orientation!=[orientation integerValue]) {
[[UIDevice currentDevice] setValue:orientation forKey:@"orientation"];//让设备竖屏
//点击按钮是让设备竖屏
}
}
};
如果你对self.webView.scrollView设置了属性监听 你需要在dealloc里移除监听者 这是大家都知晓的
但是你在写这行self.webView = nil;代码之前 也必须移除观察者 不然后在11以下的系统上崩溃 崩的无任何提示!
- 正则匹配字符串中的数字
- (NSMutableAttributedString*)returnArrtStrWith:(NSString*)str
{
if (!str.length) {
return [[NSMutableAttributedString alloc]initWithString:@""];
}
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[0-9]+" options:0 error:nil];
NSArray *numArr = [regex matchesInString:str options:0 range:NSMakeRange(0, [str length])];
NSMutableAttributedString * attr = [[NSMutableAttributedString alloc]initWithString:str];
for (NSTextCheckingResult *attirbute in numArr) {
[attr setAttributes:@{NSForegroundColorAttributeName:HWColor(255, 212, 0)} range:attirbute.range];
}
return attr;
}