App开发过程中,总会遇到很多问题,这次把遇到的一些问题记录下来,方便自己下次遇到的时候知道怎么解决
- UITextView链接不能点击,因为设置selectable为no,需要可选择时才能点击
- Storyboard中设置hex颜色,颜色-custome-第二个tab-切换到RGB Sliders最下面有hex color
- CAShapeLayer的path不需要x和y,否则会偏离,只需要设置layer的frame即可
- 获取autolayout之后的view的frame,调用layoutIfNeeded即可
- 导航栏白色,在infoplist中设置即可Status bar style和View controller-based status bar appearance即可
- corner和shadow同时设置,可以在视图后面加一个layer设置border
- 拉伸图片
(1)stretchableImageWithLeftCapWidth指定拉伸图片位置
(2)在xcode里面直接设置图片 - automaticallyAdjustsScrollViewInsets设置viewcontroller自动适应内部的scrollview高度
- 自定义cell和sectionheaderfooter时,需要重写initWithReuseIdentifier方法,在里面添加自定义view
- tableview调用reload/delete/insertRowsAtIndexPaths方法时,必须时已经存在的行,否则会崩溃提示找不到对应的的行;此时应该使用reloaddata
- weak-strong使用了yykit里面的宏定义YYKit
- 在类别中定义属性,使用runtime进行动态绑定,在set和get中实现对应的objc_setAssociatedObject和objc_getAssociatedObject方法即可
- 想要监听animationDidStop,需要将动画的removedOnCompletion属性设置为NO,否则代理事件触发时动画已经被移除,导致监听到的动画和创建的动画不一致
- removedOnCompletion为NO会导致内存泄漏问题,需要手动调用removeAnimationForKey方法移除动画
- layer和sublayer理解
self.layer insertSublayer:below:会插入layer到当前view的layer上面,上一层,不是和当前layer一层;
想要在一个层级使用self.superview.layer insertSublayer:below:方法 - method swizzling
dispatch_once(&viewToken, ^{ SEL originSelector = @selector(setBackgroundColor:); SEL overrideSelector = @selector(setBackgroundColorWithGradientLayer:); Method originMethod = class_getInstanceMethod([self class], originSelector); Method overrideMethod = class_getInstanceMethod([self class], overrideSelector); //@return YES if the method was added successfully, otherwise NO //* (for example, the class already contains a method implementation with that name). BOOL addSuccess = class_addMethod([self class], originSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(originMethod));//[self class]已经包含originSelector,所以这里总是返回NO if (addSuccess) {//如果已经添加了新方法(originSEL + overrideIMP),就替换overrideSEL的IMP为originIMP //* @note This function behaves in two different ways: //* - If the method identified by e name does not yet exist, it is added as if c class_addMethod were called. //* The type encoding specified by e types is used as given. //* - If the method identified by e name does exist, its c IMP is replaced as if c method_setImplementation were called. //* The type encoding specified by e types is ignored. class_replaceMethod([self class], overrideSelector, method_getImplementation(originMethod), method_getTypeEncoding(originMethod)); } else {//交换两个方法的IMP //* @note This is an atomic version of the following: //* code //* IMP imp1 = method_getImplementation(m1); //* IMP imp2 = method_getImplementation(m2); //* method_setImplementation(m1, imp2); //* method_setImplementation(m2, imp1); //* endcode method_exchangeImplementations(originMethod, overrideMethod); } });
- 对于复杂的view或者controller,重写dealloc方法,看是否被释放
- Storyboard中自定义tableviewcell,不需要再controller中注册,直接使用即可
- Storyboard中不能添加约束?一开始就拖动到cell里面,不要从外面拖进去,外面拖进去的不能修改了
- scrollview,textview添加约束,需要加width和height约束
- Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x282291a90 CustomCountTextView:0x128812000.height >= 60>,实际高度和storyboard中设置的高度不一致导致冲突,通过就该约束优先级解决 - uitextview可以通过textContainerInset属性设置输入区域
- 滑动返回,导航栏黑块,设置navigationcontroller的背景颜色即可
- didDeselectRowAtIndexPath不执行,因为设置完数据之后刷新了cell,失去了选择状态,所以不会执行取消选择的方法
- 手动创建view,view上有子view以它为基准定位时,view初始化时需要设置一个size,否则会报不能满足约束错误
- 延时规范写法 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.001 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{});
- wkwebview设置背景色,需要在代理方法
didFinishNavigation
中设置webView.scrollView.backgroundColor = [UIColor greenColor];
- xib中自定义view需要等比例放大缩小时,需要设置
contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- 使用cashapelayer通过mask设置圆角时,在xib中创建的view会有适配问题,需要确定view的frame才能准确地切圆角。所以除非要切指定圆角再用这种方式,先设置好frame在使用
- js和原生交互,参考链接
- js可以通过url把方法或参数传给原生页面
location.href = "schema://mask?toggle=1"; // 通知App
- js里面绑定方法到window上,原生可以直接调window上的js方法
componentDidMount() { window.addNum = this.addNum.bind(this); // 暴露方法给App }
- js可以通过url把方法或参数传给原生页面
- avaudioPlayer播放声音太小,加上如下设置即可
[self.audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
- 使用runtime替换类方法时,通过objec_getClass获取类的isa指针,并把方法添加到类的superclass,即元类上才可以生效
- iOS字体适配,1需要使用UIFont分类,添加自定义systemFontOfSize:方法来替换系统的设置方法,2需要对storyboard中的可设置字体的控件添加分类,添加自定义awakefromnib方法替换系统的方法
- 项目模拟器启动报错,需要先删除可能导致问题的第三方库,在重新导入,通过podfile注释和取消注释实现,即可实现在模拟器运行项目。还不行的话添加
#if TARGET_IPHONE_SIMULATOR
宏判断是否是模拟器来进行对应的处理。 - 申请邓白氏码,要用自己的工作邮箱,带公司域名后缀的
- webkit和js交互时,如果message.body中无参数,JS代码中需要传个null,不然iOS端不会接受到JS交互,window.webkit.messageHandlers.kJS_Login.postMessage(null)
- 通过
addChildViewController
和addSubview
方式添加的子控制器,会被当前控制器强引用,使用block时需要用__weak来解除,防止循环引用。 - avplayer相关配置写在,player的set方法中,当player设置完成后,在配置player相关项目。
- avplayer切换播放内容时,使用replaceCurrentItemWithPlayerItem,而不是重新创建player
- AVCaptureSession添加输入源时,要先添加audiodevice,再添加imagedevice,否则切换摄像头时会混乱
- CATransition动画默认key为transition,不可以修改
- afnetworking检测网络变化,要用sharedmanager而不是manager,别写错了
- 不能使用super performSelector:方法调用父类的方法,回导致死循环。因为super不是父类的指针,还是当前类的对象,只是表示需要去父类查找方法
- 调用父类隐藏方法
- (void)performSelectorInSuper:(SEL)selector withObject:(id)object { //objc_msgSendSuper直接发送消息不行,需要设置superReceiver // ((void(*)(id, SEL, id))objc_msgSendSuper)(self, selector, object); if ([[self superclass] instancesRespondToSelector:_cmd]) { struct objc_super superReceiver = { self, [self superclass] }; ((void(*)(id, SEL, id))objc_msgSendSuper)((__bridge id)(&superReceiver), selector, object); } }
- 直接拖入到工程中的文件夹会被忽略,使用bundle来代替可以保持文件夹目录
检查内存泄漏问题!!!
使用真机验证页面!!!
LiveViewController:在cell中实现代理,把代理方法执行结果用block导出到controller中!!!
不同的模拟器中运行App!!!
在不同系统iOS10.0和iOS11.0的模拟器或者真机中运行App!!!
sectionheaderview 不要直接操作上面的空间,暴露一个方法传入数据进行修改!!!(只需要设置一次数据,只有一个控件的除外)
提取通用SDK,方便以后的项目中调用!!!
昨天代码已经提交测试了,最近应该不会有什么大的改动,可能只是修改bug什么的,正好有时间整理一下文档和代码。