iOS-OC常见技术点整理
2017-10-25 本文已影响25人
Simple_Code
1. 移除控件上所有得子控件
方法一:
[view.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
方法二:
- (void)removeAllSubviews {
//[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
while (self.subviews.count) {
[self.subviews.lastObject removeFromSuperview];
}
}
方法三:
[xxxView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj removeFromSuperview];
}];
2. 直接滚动到Scrollview的底部
- (void)scrollsToBottomAnimated:(BOOL)animated
{
CGFloat offset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
if (offset > 0)
{
[self.tableView setContentOffset:CGPointMake(0, offset) animated:animated];
}
}
3. 给Label文字添加行距和文字距离+计算其高度
#define UILABEL_LINE_SPACE 6
#define HEIGHT [ [ UIScreen mainScreen ] bounds ].size.height
//给UILabel设置行间距和字间距
-(void)setLabelSpace:(UILabel*)label withValue:(NSString*)str withFont:(UIFont*)font {
NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStylealloc] init];
paraStyle.lineBreakMode =NSLineBreakByCharWrapping;
paraStyle.alignment =NSTextAlignmentLeft;
paraStyle.lineSpacing = UILABEL_LINE_SPACE; //设置行间距
paraStyle.hyphenationFactor = 1.0;
paraStyle.firstLineHeadIndent =0.0;
paraStyle.paragraphSpacingBefore =0.0;
paraStyle.headIndent = 0;
paraStyle.tailIndent = 0;
//设置字间距 NSKernAttributeName:@1.5f
NSDictionary *dic =@{NSFontAttributeName:font,NSParagraphStyleAttributeName:paraStyle,NSKernAttributeName:@1.5f
};
NSAttributedString *attributeStr = [[NSAttributedStringalloc] initWithString:strattributes:dic];
label.attributedText = attributeStr;
}
//计算UILabel的高度(带有行间距的情况)
-(CGFloat)getSpaceLabelHeight:(NSString*)str withFont:(UIFont*)font withWidth:(CGFloat)width {
NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStylealloc] init];
paraStyle.lineBreakMode =NSLineBreakByCharWrapping;
paraStyle.alignment =NSTextAlignmentLeft;
paraStyle.lineSpacing = UILABEL_LINE_SPACE;
paraStyle.hyphenationFactor = 1.0;
paraStyle.firstLineHeadIndent =0.0;
paraStyle.paragraphSpacingBefore =0.0;
paraStyle.headIndent = 0;
paraStyle.tailIndent = 0;
NSDictionary *dic =@{NSFontAttributeName:font,NSParagraphStyleAttributeName:paraStyle,NSKernAttributeName:@1.5f
};
CGSize size = [strboundingRectWithSize:CGSizeMake(width,HEIGHT) options:NSStringDrawingUsesLineFragmentOriginattributes:dic context:nil].size;
return size.height;
}
4. 使用Masonry后、使frame及时生效(需要在mas_makeConstraints之后用它的父视图调用layoutIfNeeded可以使得约束立即生效
)
UIView *view = [UIView new];
[self.view addSubview:view];
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(10, 10, 10, 10));
}];
view.backgroundColor = [UIColor redColor];
[self.view layoutIfNeeded];
NSLog(@"%@",view1.description);
5. 自定义View的淡入淡出
// 淡入
- (void)fadeIn
{
self.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.alpha = 0;
[UIView animateWithDuration:.35 animations:^{
self.alpha = 1;
self.transform = CGAffineTransformMakeScale(1, 1);
}];
}
// 淡出
- (void)fadeOut
{
[UIView animateWithDuration:.35 animations:^{
self.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.alpha = 0.0;
} completion:^(BOOL finished) {
if (finished) {
[self removeFromSuperview];
}
}];
}
// 向上弹起
- (void)show{
UIWindow *currentWindows = [UIApplication sharedApplication].keyWindow;
self.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.2];
[currentWindows addSubview:self];
[UIView animateWithDuration:.3 animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
self.backView.frame = ScreenBounds;
}];
}
// 向下弹出
- (void)dissMissView{
[UIView animateWithDuration:.3 animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
self.backView.frame = CGRectMake(0, ScreenHeight, ScreenWidth, ScreenHeight);
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}
6. 图片拉伸方法(- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode
)的使用
/**
参数一:capInsets是UIEdgeInsets类型的数据,即原始图像要被保护的区域
参数二:resizingMode是UIImageResizingMode类似的数据,即图像拉伸时选用的拉伸模式
UIImageResizingModeTile, 平铺
UIImageResizingModeStretch, 拉伸
*/
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode
拉伸区域示意图.png
7. iOS中超出父视图的按钮点击事件响应处理(方法一有问题
)
方法一:
//在父控件里面重写此方法、self.launchBtn为当前控件
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView * view = [super hitTest:point withEvent:event];
if (view == nil) {
// 转换坐标系
CGPoint newPoint = [self.launchBtn convertPoint:point fromView:self];
// 判断触摸点是否在button上
if (CGRectContainsPoint(self.launchBtn.bounds, newPoint)) {
view = self.launchBtn;
}
}
return view;
}
方法二:
//重写hitTest方法,去监听发布按钮的点击,目的是为了让凸出的部分点击也有反应
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//这一个判断是关键,不判断的话push到其他页面,点击发布按钮的位置也是会有反应的,这样就不好了
//self.isHidden == NO 说明当前页面是有tabbar的,那么肯定是在导航控制器的根控制器页面
//在导航控制器根控制器页面,那么我们就需要判断手指点击的位置是否在发布按钮身上
//是的话让发布按钮自己处理点击事件,不是的话让系统去处理点击事件就可以了
if (self.isHidden == NO) {
//将当前tabbar的触摸点转换坐标系,转换到发布按钮的身上,生成一个新的点
CGPoint newP = [self convertPoint:point toView:self.publishButton];
//判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮
if ( [self.publishButton pointInside:newP withEvent:event]) {
return self.publishButton;
}else{//如果点不在发布按钮身上,直接让系统处理就可以了
return [super hitTest:point withEvent:event];
}
}
else {//tabbar隐藏了,那么说明已经push到其他的页面了,这个时候还是让系统去判断最合适的view处理就好了
return [super hitTest:point withEvent:event];
}
}
8. 获得Xcode里面所有字体的字体样式
// 获取字体样式
NSArray *familyNames = [UIFont familyNames];
for( NSString *familyName in familyNames )
{
NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName];
for( NSString *fontName in fontNames )
{
printf( "\tFont: %s \n", [fontName UTF8String] );
}
}
// 使用字体
self.label.text = @"login";
self.label.font = [UIFont fontWithName:@"Century-GothicT." size:30];
9. Xcode里面中文文字设置斜体
// ios中不支持中文倾斜,于是只有设置倾斜角度。
// 第一行代码:设置反射。倾斜15度。
CGAffineTransform matrix = CGAffineTransformMake(1,0,tanf(15*(CGFloat)M_PI/180),1,0,0);
// 第二行代码:取得系统字符并设置反射。
UIFontDescriptor *desc = [ UIFontDescriptor fontDescriptorWithName:[UIFont systemFontOfSize :17 ]. fontName matrix :matrix];
// 第三行代码:获取字体。
UIFont *font = [UIFont fontWithDescriptor:desc size :17];
10. + initialize 与 +load调用时机
load 方法会在加载类的时候就被调用,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法。
initialize 方法类似一个懒加载,如果没有使用这个类,那么系统默认不会去调用这个方法,且默认只加载一次; initialize 的调用发生在 +init 方法之前。
11. 更改webViewl里面html的字体样式
NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"enLATP" ofType:@"html"];
NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
UIFont *font = [UIFont fontWithScaledSize:14];
UIFont *font1 = [UIFont fontWithBigSize:16];
NSString *fontColor = @"CCCCFF";
NSString *fontColor1 = @"000000";
NSString *htmlString =[NSString stringWithFormat:@"<html> \n"
"<head> \n"
"<style type=\"text/css\"> \n"
"body {font-family: \"%@\"; color: %@;}\n"
".boldFont {font-family: \"%@\"; color: %@;}\n"
"</style> \n"
"</head> \n"
"<body>%@</body> \n"
"</html>", font.familyName,fontColor,font1.familyName,fontColor1,appHtml];
if(htmlPath.length==0)
{
return;
}
NSURL *baseURL = [NSURL fileURLWithPath:htmlPath];
[self.webView loadHTMLString:htmlString baseURL:baseURL];
12. 点击屏幕键盘退出
- (void)sp_addReturnKeyBoard {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
tap.numberOfTapsRequired = 1;
tap.numberOfTouchesRequired = 1;
[tap.rac_gestureSignal subscribeNext:^(id x) {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.window endEditing:YES];
}];
[self addGestureRecognizer:tap];
}
13. 通知标准写法(建议使用)
// Foo.h
UIKIT_EXTERN NSNotificationName const ZOCFooDidBecomeBarNotification
// Foo.m
NSNotificationName const ZOCFooDidBecomeBarNotification = @"ZOCFooDidBecomeBarNotification";
14. 获取APP当前所在的ViewController
- (UIViewController *)findBestViewController:(UIViewController*)vc {
if (vc.presentedViewController) {
// Return presented view controller
return [self findBestViewController:vc.presentedViewController];
} else if ([vc isKindOfClass:[UISplitViewController class]]) {
// Return right hand side
UISplitViewController* svc = (UISplitViewController*) vc;
if (svc.viewControllers.count > 0)
return [self findBestViewController:svc.viewControllers.lastObject];
else
return vc;
} else if ([vc isKindOfClass:[UINavigationController class]]) {
// Return top view
UINavigationController* svc = (UINavigationController*) vc;
if (svc.viewControllers.count > 0)
return [self findBestViewController:svc.topViewController];
else
return vc;
} else if ([vc isKindOfClass:[UITabBarController class]]) {
// Return visible view
UITabBarController* svc = (UITabBarController*) vc;
if (svc.viewControllers.count > 0)
return [self findBestViewController:svc.selectedViewController];
else
return vc;
} else {
// Unknown view controller type, return last child view controller
return vc;
}
}
- (UIViewController*) currentViewController {
// Find best view controller
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController;
return [self findBestViewController:viewController];
}
调用
UIViewController * viewControllerNow = [self currentViewController];
if ([viewControllerNow isKindOfClass:[PCBConversationController class]]) { //如果是页面XXX,则执行下面语句
item.badgeValue = nil;
}else{}
15. 通知的注册和移除
-(void) viewWillAppear:(BOOL)animated 方法里面注册
-(void) viewWillDisappear:(BOOL)animated;方法里面移除
16.判断当前页面是Push过来还是present过来
方法一:
通过判断self有没有present方式显示的父视图presentingViewController
if (self.presentingViewController) {
[self dismissViewControllerAnimated:YES completion:nil];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
方法二:(若果present的ControllView的带有UINavigationBar不能使用此方法)
通过判断self有没有present方式显示的父视图
if (self.navigationController.topViewController == self) {
[self.navigationController popViewControllerAnimated:YES];
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}
17. CollectioView滚动到指定section的方法
https://www.cnblogs.com/tinych/p/5891665.html
18.查看自己编写的代码行数
1. cd到代码的文件夹下面
2. 然后编辑一下命令
find . "(" -name "*.m" -or -name "*.mm" -or -name "*.cpp" -or -name "*.h" -or -name "*.rss" ")" -print | xargs wc -l
19.新特性页面渐隐跳转到主页面
#pragma mark - 使页面动态消失
- (void)restoreRootViewController:(UIViewController *)rootViewController {
[UIView transitionWithView:[UIApplication sharedApplication].keyWindow duration:0.5f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
BOOL oldState = [UIView areAnimationsEnabled];
[UIView setAnimationsEnabled:NO];
[UIApplication sharedApplication].keyWindow.rootViewController = rootViewController;
[UIView setAnimationsEnabled:oldState];
} completion:nil];
}
使用方法
// 设置跟控制器
PCBLoginController *loginVc = [[PCBLoginController alloc]init];
CTNavigationController *naVc = [[CTNavigationController alloc]initWithRootViewController:loginVc];
// 切换控制器
[self restoreRootViewController:naVc];
使用CATransition方法达到此效果
// 跳转到核心界面,push,modal,切换跟控制器的方法
KeyWindow.rootViewController = [[TabBarController alloc] init];
CATransition *anim = [CATransition animation];
anim.duration = 0.5;
anim.type = @"rippleffect";
[KeyWindow.layer addAnimation:anim forKey:nil];
20.货币价格计算,使用float类型运算,经常出现误差。
在iOS开发中,经常遇到和货币价格计算相关的,这时就需要注意计算精度的问题。使用float类型运算,经常出现误差。为了解决这种问题我们使用NSDecimalNumber,下面将通过例子的形式给大家展示一下。
点击查看
21.解决APP切入到后台,倒计时停止的问题
- (void)applicationDidEnterBackground:(UIApplication *)application {
UIApplication *app = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask;
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid){
bgTask = UIBackgroundTaskInvalid;
}
});
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
if (bgTask != UIBackgroundTaskInvalid){
bgTask = UIBackgroundTaskInvalid;
}
});
});
}
22.ScrollView滚动动画的三种方式
- begin 和 commit
[UIView beginAnimations:nil context: nil];
[UIView setAnimationDuration:2.0];
[UIView setAnimationDelegate:self]; // 代理
[UIView setAnimationDidStopSelector:@selector(stop)];
[UIView setAnimationWillStartSelector:@selector(start)];
CGFloat offsetX = self.scrollView.contentSize.width - self.scrollView.frame.size.width;
self.scrollView.contentOffset = CGPointMake(offsetX, self.scrollView.contentOffset.y);
[UIView commitAnimations];
- block
[UIView animateWithDuration:2.0 animations:^{
self.scrollView.contentOffset = CGPointMake(0, self.scrollView.contentOffset.y);
}];
- 某些属性有其特有的动画
CGPoint offset = CGPointMake(self.scrollView.contentOffset.x, 0);
[self.scrollView setContentOffset:offset animated:YES];
23.RAC注销通知的两种方法
方法一:
//代替通知
//takeUntil会接收一个signal,当signal触发后会把之前的信号释放掉
[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) {
NSLog(@"键盘弹出");
}];
方法二:
//这里这样写只是为了给大家开拓一种思路,selector的方法可以应需求更改,即当这个方法执行后,产生一个信号告知控制器释放掉这个订阅的信号
RACSignal * deallocSignal = [self rac_signalForSelector:@selector(viewWillDisappear:)];
[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"haha" object:nil] takeUntil:deallocSignal] subscribeNext:^(id x) {
NSLog(@"haha");
}];
24.消除警告
1.关于编译器:关闭警告:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
代码
#pragma clang diagnostic pop
2.忽略没用的变量
#pragma unused (foo)
明确定义错误和警告
#error Whoa, buddy, you need to check for zero here!
#warning Dude, don't compare floating point numbers like this!
25.导航栏显示和隐藏(只能进行显示和隐藏两者之间的切换、不能进行隐藏和隐藏之间的切换(这个有bug)
)
将animated属性继承ViewWillAppear(Disappear)的animated属性即可
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
26.使用Masonry计算cell高度titleLabel
为最下面元素
//注意:这是写这篇文章的重中之重,核心代码
+ (CGFloat)heightWithModel:(ECHelpListModel *)model{
ECHelpListDetailCell *cell = [[ECHelpListDetailCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@""];
[cell setModel:model];
[cell layoutIfNeeded];
return cell.titleLabel.bottom + 10;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
//取出model
HHPollingItemsModel *model = self.items[indexPath.row];
return [HHPollingDetailCell heightWithModel:model];
}
model 懒加载计算高度自己常用的方法
//.h
@property (nonatomic, assign) CGFloat cellHeight;
//.m
- (CGFloat)cellHeight {
// 如果cell的高度已经计算过, 就直接返回
if (_cellHeight) return _cellHeight;
_cellHeight = 0;
_cellHeight++......// 计算高度的一系列操作
return _cellHeight;
}
//调用:
//计算cell的高度(在model里面计算)
return self.dataArray[indexPath.row].cellHeight;
参考地址:http://www.cocoachina.com/ios/20171212/21504.html
27.判断子view是否添加到父view上
if ([subView isDescendantOfView: parentView]) {
NSLog(@"已添加上");
}
28.UIView强制赋值图片
// 跨框架赋值需要进行桥接
self.view.layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"123"].CGImage);
29.判断类里面是否有实现某个方法
//判断wearNeat方法有没有在Student中实现了
if([stu respondsToSelector:@selector(wearNeat)]){
[stu wearNeat];
}
30.给有问题的代码打警告
#warning 代码过几天在补充