TableView长截图
UIImage *image = nil;
// 下面的方法,第一个参数表示区域大小。第二个参数表示是否是非透明的。如果需要显示半透明效果,需要传NO,否则传YES。第三个参数就是屏幕密度了,调整清晰度。
UIGraphicsBeginImageContextWithOptions(self.tableView.contentSize, YES, [UIScreen mainScreen].scale);
CGPoint savedContentOffset = self.tableView.contentOffset;
CGRect savedFrame = self.tableView.frame;
self.tableView.contentOffset = CGPointZero;
self.tableView.frame = CGRectMake(0, 0, self.tableView.contentSize.width, self.tableView.contentSize.height);
[self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
self.tableView.contentOffset = savedContentOffset;
self.tableView.frame = savedFrame;
UIGraphicsEndImageContext();
UIColor添加透明度
UIColor *color = [[YMSkinHelper single] skinColor];
CGFloat red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
color = [UIColor colorWithRed:red green:green blue:blue alpha:0.3];
关于setObject
和setValue
方法的区别
NSString *test = nil;
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
[dic setObject:@"1" forKey:@"key1"];
//[dic setObject:@"1" forKey:test];//key不能为nil,崩溃.
//[dic setObject:test forKey:@"key2"];//object不能为nil,崩溃.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setValue:@"1" forKey:@"key1"];
//[dict setValue:@"1" forKey:test];//key不能为nil,崩溃.
[dict setValue:test forKey:@"key2"];//value可以为nil,不会崩溃,但是会调用removeObject:forKey方法导致key2键值对不存在.
NSLog(@"%@ %@", dic, dict);
iOS开发 调用手机微微震动效果
1. 导入框架
#import <AudioToolbox/AudioToolbox.h>
2.调用震动方法,一句代码解决
// 普通短震,3D Touch 中 Pop 震动反馈
AudioServicesPlaySystemSound(1520);
// 普通短震,3D Touch 中 Peek 震动反馈
AudioServicesPlaySystemSound(1519);
// 连续三次短震
AudioServicesPlaySystemSound(1521);
UIView设置阴影时需要注意
// 投影
// _progressView.layer.masksToBounds = YES;
_progressView.layer.cornerRadius = 4;
_progressView.backgroundColor = RGB(28, 151, 255);
_progressView.layer.shadowRadius = 5;
_progressView.layer.shadowOpacity = 0.75;
_progressView.layer.shadowOffset = CGSizeMake(0, 3);
_progressView.layer.shadowColor = RGB(52, 121, 249).CGColor;
在通过这样的方式设置阴影时,必须把父视图的masksToBounds属性关掉,因为阴影设置的方式就是加offset给超出视图部分设置颜色来实现的,一旦不让子视图超出,阴影也就看不出了。查看更多解决方案...
iOS UILabel 圆角与阴影共存
_textLabel.layer.backgroundColor = RGB(8, 92, 115).CGColor;
//_textLabel.layer.masksToBounds = YES;
_textLabel.layer.cornerRadius = _textLabel.height/2;
_textLabel.layer.shadowColor = RGB(8, 92, 115).CGColor;
_textLabel.layer.shadowOffset = CGSizeMake(0, 5);
_textLabel.layer.shadowOpacity = 5;
iOS11 Xcode9 [_tableView reloadData] 刷新tableView跳动问题解决办法
_tableView.estimatedRowHeight = 0;
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;
更多关于 iOS11的适配问题,详见10分钟适配 iOS 11 & iPhone X
iOS 10.3 UILabel 中划线失效
// iOS10.3系统的一个Bug,在UILable中含有中文时,中划线会失效
[attStr addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlinePatternSolid | NSUnderlineStyleSingle) range:defaultRange];
// 解决办法
[attStr addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:defaultRange];
[attStr addAttribute:NSBaselineOffsetAttributeName value:@(NSUnderlineStyleSingle) range:defaultRange];
Xcode编译报 duplicate symbols for architecture arm64
ld: 10 duplicate symbols for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
原因
- 查看自己项目中是否有重复命名的文件
(一般就是这个问题,如果项目中排查后,没有发现,就该项目所在的文件是否有重复命名的文件,删除一个就可以了,排查的目标一般都在报错前面列举出来了)
- 再查看是否在编辑 #improt 头文件时候,不小心把 .h 误写成 .m
FMDatabaseQueue lead to a deadlock
Assertion failed: (currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"),
function -[FMDatabaseQueue inDatabase:], file /Users/HaobingW/Desktop/Project/OpenSource/YMFMDB/fmdb/FMDatabaseQueue.m, line 178.
运行app,发现在“assert(currentSyncQueue != self && “inDatabase: was called reentrantly on the same queue, which would lead to a deadlock”);”这句crash掉了。
然后就去先看一下大意:
断言失败(Assertion 单元测试的时候会经常碰到),inDatabase 在相同的queue队列中被重复调用,引发死锁。
原因
在使用时,如果在queue里面的block执行过程中,又调用了 indatabase方法,则会检查 是不是同一个queue,如果是同一个queue会死锁;原因很简单:
队列里面 放了一个block,该block又在 本队列 后面放了一个 block;
从而:前一个block 里面 调用了 后一个block,必须等后一个block执行完成了,
前一个block才会 出队列;
而后一个block想要执行,则又必须先等 前一个block出队列;
因此 死锁!!!!
解决方法
在indatabase的block中,不要再调用indatabase方法。这个细心一下,多数时候很容易发现。
可是有时候因代码封装等问题,大家可能很难发现问题所在。那么就来个暴力断点吧。在每一个使用indatabase的地方都 NSLog(或者print)一下一个编号。 然后crash的时候,看一下最后是哪两个相互发生的影响造成的死锁。
tabBar 图片颜色显示效果与UI切图不一致
// 创建 tabBar
UITabBarItem *homeBar = [[UITabBarItem alloc] initWithTitle:@"home"
image:[[UIImage imageNamed:@"tab_home_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
selectedImage:[[UIImage imageNamed:@"tab_home_light"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
为了防止系统渲染,必须以UIImageRenderingModeAlwaysOriginal提供图片。若不以这种形式,那么提供的图片显示时会发生渲染错误的问题。
在IOS7中增加创建UITabBarItem的方法的同时新增了 UIImageRenderingMode属性
typedef NS_ENUM(NSInteger, UIImageRenderingMode) {
UIImageRenderingModeAutomatic, // Use the default rendering mode for the context where the image is used
UIImageRenderingModeAlwaysOriginal, // Always draw the original image, without treating it as a template
UIImageRenderingModeAlwaysTemplate, // Always draw the image as a template image, ignoring its color information } NS_ENUM_AVAILABLE_IOS(7_0);
}
- UIImageRenderingModeAutomatic //根据图片的使用环境和所处的绘图上下文自动调整渲染模式。
- UIImageRenderingModeAlwaysOriginal //始终绘制图片原始状态,不使用Tint Color。
- UIImageRenderingModeAlwaysTemplate //始终根据Tint Color绘制图片,忽略图片的颜色信息。
使用Copy崩溃的问题
解决方法,实现协议及方法
@interface CustomClass : NSObject <NSCopying,NSMutableCopying>
-(id)copyWithZone:(NSZone *)zone {
CustomClass *newClass = [[CustomClass alloc]init];
newClass.testString = self.testString;
return newClass;
}
侧滑手势禁用与恢复
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// 禁用侧滑返回
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// 恢复侧滑返回
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
}
locationInView 与 translationInView 的区别
locationInView: 获取到的是手指点击屏幕实时的坐标点
translationInView: 获取到的是手指移动后相对于手势起始点的偏移量
CGPoint point = [gesture locationInView:self.view];
CGPoint transPoint = [gesture translationInView:self.view];
NSLog(@"\n%f++++%f\n %f-----%f",point.x,point.y,transPoint.x,transPoint.y);
动画的暂停和恢复
//暂停动画.保存当前位置和时间
- (void)pauseSynAnimation {
CFTimeInterval pausedTime = [self.imageView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
self.imageView.layer.timeOffset = pausedTime;
}
//恢复动画
- (void)resumeSynLayer {
[self.imageView.layer removeAllAnimations];
animation.timeOffset = [self.imageView.layer convertTime:CACurrentMediaTime() fromLayer:nil] - self.imageView.layer.timeOffset;
[self.imageView.layer addAnimation:animation forKey:nil];
}
注意: animation 为动画对象,是一个全局变量.
UILabel竖直方向排列
UILabel不能设置方向竖直方向排列,但可以通过sizeToFit改变frame来实现:
CGRect labelFrame =CGRectMake(20,20,30,150);
UILabel*myLabel= [[UILabel alloc]initWithFrame:labelFrame];
myLabel.backgroundColor=[UIColor orangeColor];
NSString*text =@"今天是个好日子啊今天是个好日子啊今天是个好日子啊";
myLabel.text=text;
myLabel.numberOfLines=0;
[myLabelsizeToFit];
[self.view addSubview:myLabel];
[引自](http://www.jianshu.com/p/f8405416fc9d)
ScrollView代理方法
// 开始拖拽时调用
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;
// 结束拖拽(手指松开)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
// 结束减速,手指操作,停止滚动
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
// 结束滚动动画,非手指操作,停止滚动
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
// 正在滚动
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;
IOS 关于取消延迟执行函数
// 延迟执行函数
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray *)modes;
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
// 取消延迟执行函数
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument;
+ (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget;
关于取消延迟执行函数,如果是带参数的,那么取消时参数也要保持一致,否则将会取消失败.
// 例如:
// 30秒后执行延迟函数
[self performSelector:@selector(SyncTimeOut) withObject:nil afterDelay:30.f];
// 取消执行延迟函数
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(SyncTimeOut) object:nil];
字符串的处理
// 去除字符串中被特殊字符括住的字符
- (NSString *)handleStringWithString:(NSString *)str {
NSMutableString * muStr = [NSMutableString stringWithString:str];
while (1) {
NSRange range = [muStr rangeOfString:@"<"];
NSRange range1 = [muStr rangeOfString:@">"];
if (range.location != NSNotFound) {
NSInteger loc = range.location;
NSInteger len = range1.location - range.location;
[muStr deleteCharactersInRange:NSMakeRange(loc, len + 1)];
}else{
break;
}
}
return muStr;
}
// test
NSString *str = @"abcdef<asljsf>fed<123>cba<hhhhhhh>";
NSString *result = [self handleStringWithString:str];
NSLog(@"%@" , result); //abcdeffedcba
��/// 将数组转化为json.
+ (NSString *)jsonFromArray:(NSArray *)array
{
NSData *data=[NSJSONSerialization dataWithJSONObject:array
options:NSJSONWritingPrettyPrinted
error:nil];
if (data == nil) {
return nil;
}
NSString *str=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return str;
}
自定义View手势解决和tableview点击冲突
// 1.添加并设置代理 UIGestureRecognizerDelegate
// 2.实现代理方法,加以判断
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
//判断如果点击的是tableView的cell,就把手势给取消了
if ([NSStringFromClass([touch.view class]) isEqualToString:@"UITableViewCellContentView"]) {
//取消手势
return NO;
}
//否则手势存在
return YES;
}
Center
CGRect rect = self.bounds;
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
scrollView三个基本属性;
contentSize
苹果官方文档的解释是:The size of the content view.
所以很好理解,contentSize也就是scrollView可滚动的区域;
contentOffset
苹果官方文档的解释是:The point at which the origin of the content view is offset from the origin of the scroll view.
注意,这里标注的是 point ,是当前显示的区域的 origin 相对于整个scrollView的origin的位置;
contentInset
苹果官方文档的解释是:The distance that the content view is inset from the enclosing scroll view.
注意,这里说得是distance,四个值分别是上下左右
为 View 添加背景图
NSString *path = [[NSBundle mainBundle]pathForResource:@"ImageName"ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
self.layer.contents = (id)image.CGImage;
局部cell更新
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
传入参数就是要刷新的cell所在的indexPath组成的数组。
但,reloadItemsAtIndexPath默认会有一个动画的过程,cell内容更新的瞬间会出现原内容与新内容重叠的情况。那么使用如下方式取消该动画即可:
[UIView performWithoutAnimation:^{
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
}];
iOS --- UICollectionView中使用reloadItemsAtIndexPaths进行局部cell更新
runtime 获取某个类的方法名
// 以 NSArray 为例
unsigned int count = 0;
Method *methods = class_copyMethodList([NSArray class], &count);
for (int i = 0; i < count; i++) {
Method method = methods[i];
SEL methodSel = method_getName(method);
NSLog(@"%@", NSStringFromSelector(methodSel));
}
为 CollectionView 添加类似 tableView 的点击改变背景色的效果.
思路:可以通过在 cell 的 contentView 上添加一个 button , 在 button 的点击事件中实现背景颜色的改变等.至于 push 等操作则可以通过为 cell 添加代理实现.如下:
// 1.懒加载添加 touchBtn
- (UIButton *)touchBtn {
if (!_touchBtn) {
_touchBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_touchBtn.frame = CGRectMake(3.f, 3.f, _imageView.width-6.f, _imageView.height-6.f);
[_touchBtn addTarget:self action:@selector(onTouchCell) forControlEvents:UIControlEventTouchUpInside];
}
return _touchBtn;
}
// 2.将其添加到自定义 cell 的contentView
[self.contentView addSubview:self.touchBtn];
// 3.实现button 的点击事件
- (void)onTouchCell {
_touchBtn.alpha = 0.5f;
_touchBtn.backgroundColor = [UIColor blackColor];
__block typeof(self) weakSelf = self;
[UIView animateWithDuration: 0.4f animations:^{
weakSelf.touchBtn.backgroundColor = [UIColor clearColor];
}];
// 在 button 的点击方法中通过为 cell 添加代理,传入 indexPath 实现 cell 的 push 等操作.
[weakSelf.cellDelegate onTouchCell:weakSelf.indexPath];
}
// 4.为自定义的 cell 添加代理
@protocol YMSCCollectionCellDelegate <NSObject>
- (void)onTouchCell: (NSIndexPath *)indexPath;
@end
@property(nonatomic, weak) id<YMSCCollectionCellDelegate> cellDelegate;
// 5.回到 collectionViewController 中遵循 YMSCCollectionCellDelegate ,在返回 cell 的方法中为 cell 添加代理,并传入 indexPath.
@interface YMCommunityFindView ()<UICollectionViewDelegate, UICollectionViewDataSource, YMSCCollectionCellDelegate>
collectionCell.cellDelegate = self;
collectionCell.indexPath = indexPath;
// 6.实现协议中的方法
#pragma mark - YMSCCollectionCellDelegate
- (void)onTouchCell:(NSIndexPath *)indexPath {
// to do push...
}
当然,除了通过添加 button 外,还可以通过为 collectionCell 上添加单击手势,push 的实现依然可以通过设置代理实现.
__block typeof(self) weakSelf = self;
[self.contentView addTapGesture:^{
[UIView animateWithDuration:0.1f animations:^{
weakSelf.orderDetail.backgroundColor = RGBA(0, 0, 0, 0.1);
} completion:^(BOOL finished) {
weakSelf.orderDetail.backgroundColor = [UIColor whiteColor];
[weakSelf.cellDelegate onTouchCell:weakSelf.indexPath];
}];
}];
iOS关于BOOL 值的处理(一次很逗比的 bug 事件).
问题描述:服务端定义了一个 bool类型的变量返回true / false ,通过网页 json 解析也可以明确知道它是一个 bool 类型的值.
"cornerMark": 0,
"friendshipType": 0,
"id": 1040410,
"isApply": 0,
"isZan": false, //服务端定义的 bool 类型变量
"publisher": 103095882,
"publisherName": "Harryoil",
然后客户端通过网络请求后拿不到值,Xcode debug 显示值为 no summary.此外, 更奇怪的是,所有服务端定义的 bool 类型的值,客户端都显示为no summary
解决过程:关于此类问题,我在 CocoaChina 上面也遇到了同样的疑惑,具体可参考这里 ,然而并没有得到解决办法.几经折腾,依然无法拿到正常的 bool 值, 这个时候我们开始怀疑是不是自己封装的请求类出了问题,于是开始入坑查找,结局很明显,未果.一次偶然的机会,在与后端沟通的过程中了解到,其实是传参时将"uid" 传成了"userId"(这两个字段本质上都是用户的 ID, 只是服务端在改版的过程中换了个字段名而已),导致取不到任何用户相关的一些信息(比如点赞,评论信息等),总结: 沟通为先,效率至上.
iOS 崩溃日志分析
应用程序通过集成友盟的bug收集SDK, 待 App上线后,如果发生崩溃,崩溃日志将被保存下来,并上报到友盟后台,通过登录后台就能够很清楚地知道奔溃日志记录的错误信息. 要分析奔溃日志,首先需要我们保留发布时编译出来的.xcarchive
文件,该文件中保存了.dSYM
文件,通常我们可以通过打开XCode->Window->Organizer
在编译成功的文件上右键,就能打开。
通过分析.dSYM
文件定位崩溃位置的原理:Xcode 编译项目完成后,会生成一份同名的.dSYM
文件,这个文件是保存了16进制函数地址映射信息的中转文件. 当应用程序 crash 时, iOS 设备会通过 crash 日志文件保存我们每个应用程序出错函数的内存地址,通过这个函数地址去查询 dSYM 文件中对应的函数名和文件名就能精确定位到发生奔溃的地方.
什么是 dSYM 文件 ?
Xcode编译项目后,我们会看到一个同名的 dSYM 文件,dSYM 是保存 16 进制函数地址映射信息的中转文件,我们调试的 symbols 都会包含在这个文件中,并且每次编译项目的时候都会生成一个新的 dSYM 文件,对于每一个发布版本我们都很有必要保存对应的 Archives 文件.
**dSYM 文件有什么作用 ? **
当我们软件 release 模式打包或上线后,不会像我们在 Xcode 中那样直观的看到用崩溃的错误,这个时候我们就需要分析 crash report 文件了,iOS 设备中会有日志文件保存我们每个应用出错的函数内存地址,通过 Xcode 的 Organizer 可以将 iOS 设备中的 DeviceLog 导出成 crash 文件,这个时候我们就可以通过出错的函数地址去查询 dSYM 文件中程序对应的函数名和文件名。大前提是我们需要有软件版本对应的 dSYM 文件,这也是为什么我们很有必要保存每个发布版本的 Archives 文件了。
引自dSYM文件分析工具的开发者answerhuang
附:
手动解析CrashLog之原理篇
手动解析CrashLog之----方法篇
dSYM文件分析工具下载地址 密码: vtce
iOS8下发送通知NSNotification崩溃
在StoreAllOrderTableView
类中,数据请求成功以后发送如下通知:
// 发送刷新红点的通知
[[NSNotificationCenter defaultCenter] postNotificationName: YM_STORE_ORDER_WAIT_COUNT object:nil];
在StoreTopBarTool
中添加观察者
//添加观察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshCount:) name: YM_STORE_ORDER_WAIT_COUNT object:nil];
//通知中方法的实现
- (void)refreshCount:(NSNotification *)notification {
something to do...
}
现象: 在 iOS8 系统下由于存在未被释放的通知,当重复发送通知的时候发生崩溃
原因: 没有在 dealloc 中移除通知
解决办法: 在接受通知的类或者界面里的delloc方法中移除通知,如下:
在StoreTopBarTool
的dealloc
方法中移除观察者
- (void)dealloc {
//移除刷新红点的通知
[[NSNotificationCenter defaultCenter] removeObserver:self name:YM_STORE_ORDER_WAIT_COUNT object:nil];
}
注意:
-
-(void)addObserver
和-(void)removeObserver
方法中的self必须是同一个对象. - 对于此次崩溃,笔者反复验证,在 iOS9/10下并不会发生,具体什么原因可参考苹果其官方文档中的一段话:iOS9 中,NSNotificationCenter将不再会对一个已经被释放掉的observer发送通知.
In OS X 10.11 and iOS 9.0 NSNotificationCenter and NSDistributedNotificationCenter
will no longer send notifications to registered observers that may be deallocated.
更多关于 iOSNSNotification 的用法可参考
iOS通知机制
iOS NSNotificationCenter 使用姿势详解
记一次Block死循环事故
笔者在一次开发过程中,不小心在定时器结束的 Block 中回调的时候又重置了定时器导致,从而引发了这次死循环血案,导致三位测试小伙伴的 iPad/iPhone 直接bong~关机...
self.timeCountView.timeStopBlock = ^{
// 倒计时结束,关闭定时器.
dispatch_source_cancel(_timer);
_timer = nil;
dispatch_async(dispatch_get_main_queue(), ^{
if (self.timeStopBlock) {
self.timeStopBlock();
}
});
}
附: 关于 Block 循环引用的相关案例可以参考这篇文章iOS容易造成循环引用的三种场景,就在你我身边!
Block 块回调定位
// Block 重命名
typedef void(^LocationBlock)(NSIndexPath *indexPath);
// .h声明属性
@property (nonatomic, strong) LocationBlock locationBlock;
// .m传值
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:section];
if (self.locationBlock) {
self.locationBlock(indexPath);
}
// 在需要定位的地方回调Block并实现定位
__weak UICollectionView *weakCollectionView = _collectionView;
_otherRecordListView.locationBlock = ^(NSIndexPath *indexPath){
if (indexPath.item != 0 && weakSelf.itemData.count != 0) {
[weakCollectionView scrollToItemAtIndexPath:indexPath atScrollPosition:(UICollectionViewScrollPositionTop) animated:YES];
}
};
GCD timer定时器
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
dispatch_source_set_event_handler(timer, ^{
//@"倒计时结束,关闭定时器"
dispatch_source_cancel(timer);
dispatch_async(dispatch_get_main_queue(), ^{
});
});
//启动定时器
dispatch_resume(timer);
跳转至指定视图控制器
for (UIViewController *vc in self.navigationController.viewControllers) {
if ([vc isKindOfClass:[YourViewController class]]) {
[self.navigationController popToViewController:vc animated:YES];
}
}
由视图找到其所在的控制器
- (UIViewController *)viewController
{
for (UIView *next = [self superview]; next; next = next.superview) {
UIResponder *nextResponder = [next nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)nextResponder;
}
}
return nil;
}
for (UIView *next = [self superview]; next; next = next.superview) {
UIResponder *nextResponser = [next nextResponder];
NSLog(@"%@", [nextResponser class]);
if ([nextResponser isKindOfClass:[HomeView class]]) {
HomeView *view = (HomeView *)nextResponser;
break;
}
}
移除指定的视图控制器
for (UIViewController *vc in self.navigationController.childViewControllers) {
if ([vc isKindOfClass:[YourSelfViewController class]]) {
[vc removeFromParentViewController];
}
}
addSubview和 insertSubView 区别
A addSubview B 将B直接覆盖在A的最上层
A insertSubView B AtIndex:2 将B插入到A的子视图index为2的位置(最底下是0)
A insertSubView B aboveSubview:C 将B插入A并且在A已有的子视图C的上面
A insertSubView B belowSubview:C 将B插入A并且在A已有的子视图C的下面
Color转Image
+(UIImage*) createImageWithColor:(UIColor*) color
{
CGRect rect=CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
网络请求图片并缓存至本地沙盒
// SD下载
__block typeof(self) weakSelf = self;
[_userHeadBtn sd_setImageWithURL:[NSURL URLWithString:userInfo.avatarUrl] forState:UIControlStateNormal placeholderImage:headImage options:SDWebImageRetryFailed|SDWebImageContinueInBackground completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (image) {
[weakSelf saveUserHeadImg:image andUserId:userId];
}
}];
// 缓存至本地沙盒
-(void)saveUserHeadImg:(UIImage *)headImg andUserId:(NSInteger)userId
{
if (userId == 0) {
return;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"%ziavatar.png",userId]];
if (filePath && headImg)
{
[UIImagePNGRepresentation(headImg)writeToFile: filePath atomically:YES]; // 保存成功会返回YES
}
}
检验字符串是否是邮箱
+ (BOOL)isValidateEmail:(NSString *)email {
NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
return [emailTest evaluateWithObject:email];
}
MD5加密字符串
+(NSString *)getMD_5_Str:(NSString *)str {
NSMutableString *md5Str = [[NSMutableString alloc]initWithCapacity:CC_MD5_DIGEST_LENGTH*2];
const char *cStr = [str UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(cStr, (CC_LONG)strlen(cStr), result); // This is the md5 call
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[md5Str appendString:[NSString stringWithFormat:@"%02x",result[i]]];
}
return md5Str;
}
开发工具链接
SimPholders_2.2(解压密码xclient.info) 密码:uyws
dSYM文件分析工具 密码:vtce
自定义贝塞尔曲线值的Mac工具
打包APP时报错 linker command failed with exit code 1 (use -v to see invocation)
Build Settings中,把 Enable Bitcode 设置为 NO
若显示**xxx.app已损坏,打不开.你应该将它移到废纸篓 **
解决办法:
- 修改系统配置:系统偏好设置... -> 安全性与隐私。修改为任何来源
- 如果没有这个选项的话(macOS Sierra 10.12),打开终端,行命令:
sudo spctl --master-disable
Xcode相关
// Xcode8注释快捷键失效
解决方法:命令运行 sudo /usr/libexec/xpccachectl ,然后必须重启电脑后生效
// Xcode模拟器缓存路径
~/Library/Developer/Xcode/DerivedData/ModuleCache
防止谷歌自动跳转到香港google.com.hk解决办法
具体做法:在网址栏打入http://www.google.com/ncr,然后回车即可。如果清理了Cookies缓存,还是出现自动跳转现象,重新再在网址栏打入http://www.google.com/ncr输入,回车就行
ncr 是 no country redirection,是强制不跳转命令
git push 时报以下信息,使用命令后依然无法解决:
fatal: The current branch master has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin master
Jietu20170705-115347.jpg
解决办法 : 如果不想重新创建远程仓库再克隆,或者初始化本地仓库,可以使用下面命令:
git push -u origin master
,其中origin 表示远程仓库名称,master是远程仓库的push目标分支。-u (推测为update缩写_~) 表示本地分支将建立对远程仓库目标分支的检测,如果远程仓库目标分支不存在,将新建分支再push;如果存在,将进行push更新
Instead of creating a new repository on Github, cloning that, or reinitializing your local repository, the following command would have been sufficient:
git push -u origin master
origin stands for the remote name (default is origin), and master is the branch you want to push, in your case it's master, otherwise you would have to change that in the command.
-u means, that your local branch will be setup to track the new created master branch on the origin repository (the master on the origin will be the upstream branch of your local branch). If the branch master doesn't exist on the remote repository, it will be created, otherwise it will be updated (the -u works no matter if it exists or not).
然后,验证此方法,确实可行!
引自
npm执行命令时出错
npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules/gitbook/node_modules/abab'
npm ERR! { [Error: EACCES: permission denied, access '/usr/local/lib/node_modules/gitbook/node_modules/abab']
npm ERR! stack:
npm ERR! 'Error: EACCES: permission denied, access \'/usr/local/lib/node_modules/gitbook/node_modules/abab\'',
npm ERR! errno: -13,
npm ERR! code: 'EACCES',
npm ERR! syscall: 'access',
npm ERR! path: '/usr/local/lib/node_modules/gitbook/node_modules/abab' }
npm ERR!
npm ERR! The operation was rejected by your operating system.
npm ERR! It is likely you do not have the permissions to access this file as the current user
npm ERR!
npm ERR! If you believe this might be a permissions issue, please double-check the
npm ERR! permissions of the file and its containing directories, or try running
npm ERR! the command again as root/Administrator (though this is not recommended).
网友评论