iOS 给自定义视图添加高亮背景色

UITableView的默认Cell,是有点击选中的高亮背景色的,UIButton也可以通过设置不同状态的背景图片来实现高亮,那么如何给自定义视图添加高亮呢? 一个技术上可行的方法就是重写UIView的各种touches方法,自己记录点击选中,点击取消等状态,不过很繁琐。 还有一个是重写UIControl的下面四个方法,下面四个方法将点击选中,取消等状态处理简化了 //是否可以开始追踪事件 - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event; //是否持续追踪事件 - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event; //事件追踪结束 - (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event; // touch is sometimes nil if cancelTracking calls through to this. //事件追踪取消 - (void)cancelTrackingWithEvent:(nullable UIEvent *)event; // event may be nil if cancelled for non-event reasons, e.g. 具体示例 - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event { BOOL b = [super beginTrackingWithTouch:touch withEvent:event]; if (b) { 如果开始追踪,那么就高亮显示 [super setBackgroundColor:高亮色]; } return b; } - (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event { [super endTrackingWithTouch:touch withEvent:event]; //结束追踪 恢复原始背景色 [super setBackgroundColor:原始背景色]; } - (void)cancelTrackingWithEvent:(nullable UIEvent *)event { [super cancelTrackingWithEvent:event]; //取消追踪 恢复原始背景色 [super setBackgroundColor:原始背景色]; }

June 16, 2020 · 1 min · holdsky

UITableView attempt to delete section 1, but there are only 1 sections before the update

虽然提示是删除一个section,但不一定显式调用了deleteSection接口,还有可能是reloadSection,一个复现的场景就是reload了一个不存在的section。 例如 //以下为示意代码 tableview = [UITableView alloc] initWithFrame:CGRectMake(0,0,100,400) style:UITableViewStylePlain]; //添加一个section [tableview.dataSource addObject:section]; //此时,只有一个section,我们reload第二个section [tableview reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone]; //崩溃 详细堆栈 Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore/UIKit-3901.4.5/UITableView.m:2040 2020-05-14 15:17:07.597057+0800 AppTest[33419:3092839] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete section 1, but there are only 1 sections before the update' *** First throw call stack: (0x187a92a48 0x1877b9fa4 0x187994e88 0x187dca654 0x18bcc5f44 0x18bcdf9d8 0x18bce0044 0x1021422a0 0x1021420bc 0x1019194e0 0x1019193b0 0x10223d8b4 0x1075817fc 0x107582bd8 0x107590c34 0x187a105e4 0x187a0b5d8 0x187a0aadc 0x1919ab328 0x18bb1863c 0x100e9cfcc 0x187894360)

May 15, 2020 · 1 min · holdsky

Java反编译工具MacOS版--JD-GUI-OSX-1.6.6

官方地址下载速度有点慢,这里备个份。 jd-gui-osx-1.6.6

May 5, 2020 · 1 min · holdsky

iOS崩溃日志定位

日志格式 先说日志格式,常见的日志格式: 日志头 + 线程堆栈 + 映像加载信息 日志头(截取我们需要的部分) # 软硬件信息 Hardware Model: iPhone9,1 Code Type: ARM-64 (Native) OS Version: iPhone OS 13.3.1 (17D50) # 崩溃原因 Exception Type: EXC_GUARD Exception Subtype: GUARD_TYPE_FD Exception Message: CLOSE on file descriptor 66 (guarded with 0x534b434869d9c32f) Exception Note: SIMULATED (this is NOT a crash) # 崩溃线程 Triggered by Thread: 44 崩溃线程信息(截取我们需要的部分) Thread 44 name: MHD-worker Thread 44 Crashed: # 调用堆栈 # 栈号 模块名 方法地址 加载地址 偏移量 0 libsystem_kernel.dylib 0x00000001aa54ae8c close + 8 1 iQiYiPhoneVideo 0x0000000100cceda0 0x1005e0000 + 7269792 2 iQiYiPhoneVideo 0x0000000100ccbde4 0x1005e0000 + 7257572 3 iQiYiPhoneVideo 0x0000000100ccc83c 0x1005e0000 + 7260220 4 iQiYiPhoneVideo 0x0000000100ccdc00 0x1005e0000 + 7265280 5 libsystem_pthread.dylib 0x00000001aa46dd8c _pthread_start + 156 6 libsystem_pthread.dylib 0x00000001aa47176c thread_start + 8 Thread 44 crashed with ARM Thread State (64-bit): x0: 0x0000000000000001 x1: 0x0000000000000000 x2: 0x0000000171516bdc x3: 0x0000000171516e00 x4: 0x0000000000000000 x5: 0x0000000000000400 x6: 0x0000000000000000 x7: 0x0000000000000000 x8: 0x0000000000000005 x9: 0x0000000000000006 x10: 0x0000000000000001 x11: 0x0000000000000000 x12: 0x0000000000000001 x13: 0x0000000000000002 x14: 0x0000000000000000 x15: 0x0000000000006dc2 x16: 0x0000000000000006 x17: 0x0000000055800000 x18: 0x0000000000000000 x19: 0x0000000109d900e0 x20: 0x0000000000000042 x21: 0x0000000171516e80 x22: 0x0000000171516f00 x23: 0x0000000000000000 x24: 0x0000000000000000 x25: 0x0000000000000000 x26: 0x0000000000000000 x27: 0x0000000000000000 x28: 0x0000000000000000 fp: 0x0000000171516c20 lr: 0x0000000100cceda0 sp: 0x0000000171516c00 pc: 0x00000001aa54ae8c cpsr: 0x60000000 esr: 0x00000000 Address size fault 二进制映像加载信息(截取我们需要的部分) ...

April 15, 2020 · 2 min · holdsky

TS2769: Property 'xxx' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes & Readonly<{}> & Readonly<{ children?: ReactNode; }>

用TypeScript开发React项目,在父子组件间传值时发生错误提示 class Page extends React.Component { render() { return <div> <NavigationBar title="标题"/> </div> } } class NavigationBar extends React.Component { render() { return <div> "返回标题" </div> } } 错误提示 No overload matches this call. Overload 1 of 2, '(props: Readonly<{}>): NavigationBar', gave the following error. Type '{ title: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<NavigationBar> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'. Property 'title' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<NavigationBar> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'. Overload 2 of 2, '(props: {}, context?: any): NavigationBar', gave the following error. Type '{ title: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<NavigationBar> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'. Property 'title' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<NavigationBar> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'. TS2769 原因是Typescript是强类型语言,如果要给组件传值,需要在接受值组的地方声明值类型,就本例而言,需要明确定义 props,本例为 NavigationBarProps ...

April 5, 2020 · 1 min · holdsky

基于npm项目初始化TypeScript项目

# 初始化npm项目 mkdir projectName cd projectName npm init # 初始化TypeScript项目 tsc --init #安装 node的ts符号生命(用于ts的静态编译检查、语法提示) npm i @types/node

April 5, 2020 · 1 min · holdsky

JavaScript如何实现sleep?

JavaScript如何实现sleep? 一般的, sleep 是将当前上下文所在的线程从执行状态转化为挂起状态,直到指定的一段实时时间过去后,再从挂起状态转化为执行状态,在sleep执行结束前,线程不会执行其他任务。 该函数使当前进程从执行状态转化为挂起状态,直到参数seconds所指定的一段实时时间过去后,或者是一个唤醒信号跟踪功能或终止进程功能的信号到来。该挂起时间由于系统的其他调度活动可能会比要求的时间长。 在ES标准中,JavaScript代码的执行环境是一个单线程环境,所以 JavaScript如何实现sleep 的本质是如何将一个线程阻塞一段时间然后继续工作。 这里的重点是 阻塞。所以,使用 promise、 generator 之类的实现是不满足这个需求的,任务调度机制本质不同,因为 promise、 generator 的本质是延迟,而不是阻塞。 在不扩展JavaScript语言底层能力的情况下,实现阻塞方式: 计算阻塞 IO阻塞 计算阻塞 也就是消耗CPU资源进行阻塞,通常是一段循环计算,在循环期间,JavaScript代码执行线程不会执行其他任务,从而达到模拟 sleep 的效果 <script type="text/javascript"> // bad implementation function sleep(milliSeconds){ var startTime = new Date().getTime(); // get the current time while (new Date().getTime() < startTime + milliSeconds); // hog cpu } } </script> 这种方式在任何标准的ES环境中都可以实现,阻塞和计时在同一个线程中完成。 IO阻塞 也就是消耗IO资源进行阻塞,通常是消耗网络IO,如 XMLHttpRequest 的同步通信。 <script type="text/javascript"> function sleep(milliSeconds) { var resource; var response; if(typeof ActiveXObject == 'undefined'){ resource = new XMLHttpRequest(); } else{ resource = new ActiveXObject("Microsoft.XMLHTTP"); } try{ resource.open('GET', 'sleep?milliSeconds=' + milliSeconds, false); resource.send(null); response = resource.responseText; // JavaScript waits for response } catch(e){ alert(e); } } </script> 这种方式是基于BS模型,Server负责计时,在指定的时间后返回响应,Browser负责阻塞。 ...

March 30, 2020 · 1 min · holdsky

移动端监听单页应用的URL变化

问题 对于Native WebView而言,Andoird/iOS都提供相应的方法/代理监听页面URL的变化。例如,Android可以重写 doUpdateVisitedHistory 方法监听URL变化,iOS可以实现 shouldStartLoadWithRequest、 decidePolicyForNavigationAction 代理监听URL变化 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { //此处检测url是否有变化 return super.shouldOverrideUrlLoading(view, url); } //UIWebView - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { //此处检测url是否有变化 return YES; } //WKWebView - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { //此处检测url是否有变化 decisionHandler(WKNavigationActionPolicyAllow); } 上述技术实现对一些前端应用能正常工作。然而,遇到单页应用(SPA)时,以上方法并不会被触发–这里涉及单页应用的实现原理,尤其是基于 hash 路由的单页应用,其 前进/后退 的问题更为突出。 解决思路 对于前端应用而言,如果开发者使用固定的框架,那么在框架的路由层面拦截监听应较为容易做到。但是实际情况是开发者使用的前端框架不确定,甚至开发者连前端框架都不用,所以我们在前端框架层面截获路由器变得不那么容易。 经过调研,要监听前端页面的URL变化,大致有两种模式: 定时器模式 观察者模式 定时器模式 定期监测URL是否变化,如100毫秒监测一次,与上次监测值对比来判断URL是否变化。定时器,前端可以使用 setInterval 来实现 var oldUrl = window.location.href; setInterval(function(){ if (oldUrl !== window.location.href) { //通知Native Url变化 oldUrl = window.location.href; } },100); 当然,Native也可以开启定时器监测 window.location.href。 定时器模式的特点是实现简单,适用范围广;缺点也显而易见,监测结果不是十分准确,性能耗用高。而其性能耗用问题在移动端将会放大,故此我们不采用此模式。 观察者模式 上面提到的 doUpdateVisitedHistory、 shouldStartLoadWithRequest、 decidePolicyForNavigationAction 的实现可以算作观察者模式。 ...

March 19, 2020 · 2 min · holdsky

emcc 将C/C++编译成没有WebAssembly支持的JavaScript

No WebAssembly support found. Build with -s WASM=0 to target JavaScript instead. 也就是 emcc -s WASM=0 c/c++文件

March 12, 2020 · 1 min · holdsky

iOS 诡异的崩溃EXC_BREAKPOINT (code=1, subcode=0x1c5691d2c)

系统 : iOS 13.3.1 机型: iPhone7 dispatch_async(_jsContextQueue, ^{ JSContext *jscontent = [[JSContext alloc] init]; [UIWebView class]; }); 看代码,按照正常思维理解, [UIWebView class]是无论如何都不应崩溃的。 起初按照惯性思维去查找僵尸变量,忙活了半天没有定位。 最终定位结果如下: 在没有调用过UIWebView的任何函数时,先在非主线程调用UIWebView方法,则会导致崩溃 本文的相关代码如下 #import "ViewController.h" #import <JavaScriptCore/JavaScriptCore.h> @interface ViewController ()<UITableViewDelegate,UITableViewDataSource> { dispatch_queue_t _jsContextQueue; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _jsContextQueue = dispatch_queue_create("jscontext", NULL); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ dispatch_async(_jsContextQueue, ^{ JSContext *jscontent = [[JSContext alloc] init]; [UIWebView class]; }); }); } @end

March 10, 2020 · 1 min · holdsky