开发小知识点总结

此篇文章会不断更新,添加一些自己项目中发现的小知识点,与君共勉.
文章同步在 个人主页,阅读体验可能好点~
==目录==
修改UISearchBar的cancel按钮为”取消”
Present一个可以调整大小的视图
iOS 8下设置cell的分割线缩进separatorInset
weakSelf, strongSelf写法
关于iOS9的定位
iOS开发中的四舍五入、进位、摸位 方法
scrollView中有两个协议方法,之前一直没在意,今天用的时候,发现有问题了,挺有意思的;
[NSDate date]返回年份错误
将视图添加到导航栏之上
Xcode调试技巧之lldb中导入UIKit
如何写一个参数不定的函数
NULL/NSNull/nil/Nil的区别与联系

修改UISearchBar的cancel按钮为"取消"
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
    searchBar.showsCancelButton = YES;
    UIView *topView = searchBar.subviews[0];
    for (id searchButtons in topView.subviews)
    {
        if ([searchButtons isKindOfClass:[UIButton class]])
        {
            UIButton *cancelButton = (UIButton *)searchButtons;
            [cancelButton setTitle:@"取消" forState:UIControlStateNormal];
            cancelButton.titleLabel.font = [UIFont systemFontOfSize:15];
            [cancelButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            break;
        }
    }
    [self.tableView reloadData];
}

Present一个可以调整大小的视图
    XSetupViewController *setupVC = [[XSetupViewController alloc] init];
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:setupVC];
    nav.modalPresentationStyle = UIModalPresentationFormSheet;
    nav.view.backgroundColor = [UIColor clearColor];
    nav.navigationBarHidden = YES;
    [self presentViewController:nav animated:YES completion:nil];
    setupVC.preferredContentSize = CGSizeMake(522, 502);

**延伸:关于模态视图的一些属性 **

** -弹出风格UIModalPresentationStyle**
1.UIModalPresentationFullScreen:
充满全屏,对于IOS7以后版本,如果弹出视图控制器的wantsFullScreenLayout设置为YES的,则会填充到状态栏下边,否则不会填充到状态栏之下。
2.UIModalPresentationPageSheet:
高度和当前屏幕高度相同,宽度和竖屏模式下屏幕宽度相同,剩余未覆盖区域将会变暗并阻止用户点击,这种弹出模式下,竖屏时跟 UIModalPresentationFullScreen的效果一样,横屏时候两边则会留下变暗的区域。
++ UIModalPresentationFormSheet风格的模态窗口,它的大小是可以进行调整的,而且它会随着键盘的弹起进行移动++
3.UIModalPresentationFormSheet:
高度和宽度均会小于屏幕尺寸,居中显示,四周留下变暗区域.
4.UIModalPresentationCurrentContext:
弹出视图控制器的弹出方式和它的父VC的方式相同.

说明:对于iphone,只有UIModalPresentationFullScreen一种风格,即使设置成其它风格也没起作用

** -弹出时的动画风格UIModalTransitionStyle**
1.UIModalTransitionStyleCoverVertical // 底部滑入。
2.UIModalTransitionStyleFlipHorizontal // 水平翻转。
3.UIModalTransitionStyleCrossDissolve // 交叉溶解。
4.UIModalTransitionStylePartialCurl // 翻页。


iOS 8下设置cell的分割线缩进separatorInset

iOS 7下, 想要设置cell的分割线缩进为0,在iOS7中只用简单的设置cell的separatorInset = UIEdgeInsetZero;
iOS 8下, 在iOS8下,上面的方法就不行啦,经过查阅资料, 终于在stackoverflow上查到了详细的说明,源地址戳这里stackoverflow;

This property isn't available on iOS 7.0 so you need to make sure you check before assigning it!
Additionally, Apple has added a property to your cell that will prevent it from inheriting your Table View's margin settings. When this property is set, your cells are allowed to configure their own margins independently of the table view. Think of it as an override.
This property is called preservesSuperviewLayoutMargins, and setting it to NO will allow the cell's layoutMargin setting to override whatever layoutMargin is set on your TableView. It both saves time (you don't have to modify the Table View's settings), and is more concise. Please refer to Mike Abdullah's answer for a detailed explanation.

什么意思呢,就让我这个英语四级的战五渣来试着翻译一下吧.

iOS8中,新加入了一个属性:preservesSuperviewLayoutMargins,呐,这个属性的加入,可以避免你的cell的外边继承自你的tableView,当你设置这个属性的时候,你可以自由的设置你的cell的外边距,而不必担心tableView和cell两者的相互影响.(翻译的好渣,你们自己去看英文吧...)


代码实现

//Setup your cell margins:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
     // Remove seperator inset
     if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
         [cell setSeparatorInset:UIEdgeInsetsZero];
     }
     // Prevent the cell from inheriting the Table View's margin settings
     if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
         [cell setPreservesSuperviewLayoutMargins:NO]; 
      }
     // Explictly set your cell's layout margins 
    if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
         [cell setLayoutMargins:UIEdgeInsetsZero]; 
    }
}

weakSelf, strongSele写法
__weak __typeof(self)weakSelf = self;
__strong __typeof(weakSelf)strongSelf = weakSelf;

关于iOS9的定位

如果你的APP不适配iOS9,就不能偷偷在后台定位,iOS9中的CLLocation新增了一个属性:allowsBackgroundLocationUpdates,而且默认值为NO

If your app uses location in the background (without showing the blue status bar) you have to set allowsBackgroundLocationUpdates to YES in addition to setting the background mode capability in Info.plist. Otherwise location updates are only delivered in foreground. The advantage is that you can now have location managers with background location updates and other location managers with only foreground location updates in the same app. You can also reset the value to NO to change the behavior.

你的代码需需要变成这样了:

_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) {
    [_locationManager requestAlwaysAuthorization];
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9) {
    _locationManager.allowsBackgroundLocationUpdates = YES;
}
[_locationManager startUpdatingLocation];

iOS开发中的四舍五入、进位、摸位 方法

1.四舍五入比较简单:

double number;
float result1 = rounding(number, 2);//保留两位
int result2 = (int)roundf(number);

2.进位方法:

float numberToRound;
int result;
numberToRound = 5.41;
result = (int)ceilf(numberToRound);
NSLog(@"ceilf(%.2f) = %d", numberToRound, result);//输出 ceilf(5.61) = 6

3.摸位方法:

numberToRound;
int result;
numberToRound = 5.61;
result = (int)floorf(numberToRound);
NSLog(@"floorf(%.2f) = %d", numberToRound, result);//输出 floorf(5.61) = 5

scrollView中有两个协议方法,之前一直没在意,今天用的时候,发现有问题了,挺有意思的;

//本来想在tableView停止滚动之后做一些事情,就调用了方法①,可是发现不会执行,就看了一下文档,恍然大悟!
①-scrollViewDidEndScrollingAnimation: //is called when a programmatic-generated scroll finishes.意思就是这个事系统级的动画执行完毕触发的
②-scrollViewDidEndDecelerating: //is called when a user-swipe scroll finishes.这个是用户自己滑动之后停止触发的

还有一点自己之前也没有注意到,** 有时候我们在拖拽的时候,手慢慢松开,这时候scrollView是跟随拖拽立即停止,注意这时候scrollViewDidEndScroll是不会触发的,我们要调用③**

③- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate:
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
//这个方法就适用于拖拽停止的场景,可以利用参数decelerate来作为判断是否拖拽之后停止OR继续减速滚动了;

[NSDate date]返回年份错误
    NSDate *date = [NSDate date];
    NSDateFormatter *formater = [[NSDateFormatter alloc] init];
    [formater setDateFormat:@"YYYY-MM-dd"];
    NSString *tempStr = [formater stringFromDate:date];

假如现在的时间是2015.12.28,以上这段代码返回值是什么?
你估计有一些人心里会想,这个二货,这么简单的问题简直是在侮辱我的智商啊!然后脱口而出:2015-12-28;
但是我想说的是,一开始我也这么想的,而且郁闷了很久,没错,返回的是2016-12-28,年份大了一年,如果想返回正确的时间,你需要把YYYY改成yyyy...虽然这个错误改正过来了,但是很纳闷,为什么会返回给我个年份大于一年的时间呢?查阅了很多资料,最后得出了答案 - ISO 8601.国际数据存储交换标准,叫做week year,以星期来规划年份,关于这个怎么个规划法,我就不说了,有点晦涩难理解,这里只说一点:
这个标准日历日期中,一年当中的最后一周有以下两个要求:

Its last day is the Sunday nearest to 31 December.

It has 28 December in it. Hence the latest possible dates are 28 December through 3 January, the earliest 21 through 28 December.
即:
If 31 December is on a Monday, Tuesday or Wednesday, it is in week 01 of the next year. If it is on a Thursday, it is in week 53 of the year just ending; if on a Friday it is in week 52 (or 53 if the year just ending is a leap year); if on a Saturday or Sunday, it is in week 52 of the year just ending.

最后一年的最后一周必须是最靠近12月31号的那个周日,如果31号是周一周二周三或者周四,那它就是下一年的第一周,如果是周五周六周日,那它是当年的最后一周
再回过头来看看我这个问题,还真是赶得巧,正好28号是周一,意味着这要算到下一年的第一周了,所以返回的年份是2016,这里也要庆幸出问题了,涨了姿势了~

将视图添加到导航栏之上

如果你有一个子视图subVC(继承自UIVIewController),它只是作为临时出现,把它添加到当前控制器CorrentViewConteoller之上并且要覆盖CorrentVC的导航栏,改如何添加呢?
这里介绍几种方法以及说明一下优缺点:

//第一种:直接添加到keyWindow上
UIWIndow *keyWindow = [[[UIApplication shareApplication] delegate] window];
[keyWindow addSubView:subVC.view];

优缺点:简单直接暴力,直接添加到最顶层的window上,但是有一个问题:首先,它会一直在最顶层,如果你需要present一个视图,而且当前subVC不能立即释放,那么在转场的时候你会发现这个烦人的subVC总是会出现在你的顶层视图;其次,这种方法添加的subVC,在屏幕发生旋转的时候,它并不会跟随旋转,自己在项目中就遇到过:程序启动的时候就去搜索蓝牙,当前屏幕还是竖屏,随后马上转为横屏,这时候弹出的提示框还是竖屏状态下的...当然这种也是有解决方案的:查看

//第二种:隐藏导航栏
[currentVC.navigationController.navigationBar setNavigationBarHidder:YES animation:YES];
[currentVC.view addSubView:subVC];
[currentVC addChildViewController:subVC];

优缺点:也比较简单直接,但是可能会对你的correntVC产生不好的影响:导致你的correntVC向上偏移64个单位,当然你可以通过重新修改它的frame解决

//第三种:添加到NavigationController的view上
[self.navigationController addChildViewController:subVC];
subVC.view.frame = self.navigationController.bounds;
[self.navigationController.view addSubjvew:subVC.view];
subVC.view.alpha = 0.0;
[subVC beginAppearanceTransition:YES animated:YES];//下面会说为何要实现这个方法
[UIView animatedWithDuration:0.4f delay:0.f option:UIViewAnimationOptionCurveEaseOut animations:^(void){
    subVC.view.alpha = 0.f;
}compation:^(BOOL finished) {
    [subVC endAppearanceTransition];
    [subVC didMoveToParentViewController:self.navigationController];
}];

优缺点:对于subVC的界面布局,需要在init方法中设置完成,同时不要忘了手动设置frame

//第四种:设置NavigationBar的zPosition达到目的
直接添加到当前View上,不需要设置导航栏隐藏,而是直接设置导航栏的zPosition为-1,默认为0,这样,我们的subVC就可以完整的显示了;
[self.view addSubView:subVC.view];
self.navigationController.navigationBar.layer.zPosition = -1;
[self addChildViewController:subVC];

优缺点:你可能注意到了,这个zPosition属性是在layer层上的,那说明什么呢?说明我们只是在渲染层面将navigation这一层隐藏了,但是它的触摸事件还是存在的,是会截断subVC在这个地方的响应的,所以这个方法并不好...

意外发现之延伸:假如我们上文提到的subVC是一个继承自UINavigationController的子视图的话,你想把它通过addSubView的方法添加到correntVC上,用来管理后面的一些视图tempVC,那么会有一个问题:在push或者pop的过程中,子视图(tempVC)的viewWillAppera,willDidAppera,viewWillDisappera等方法都不会被吊起,你需要在navigationVC的容器中手动吊起这里有一篇说明

_ _ _

>####Xcode调试技巧之lldb中导入UIKit

有时候想在断点的时候打印一下UIView的bounds,但是会出现这样的提示:
```language
(lldb) p [self bounds]
error: 'bounds' has unknown return type; cast the call to its declared return type
error: 1 errors parsing expression

这时候有计重解决办法:

//1.导入UIkit或者Foundation框架
(lldb) p @import UIKit
(lldb) po [UIScreen mainScreen].bounds
(origin = (x = 0, y = 0), size = (width = 1024, height = 768))
(origin = (x = 0, y = 0), size = (width = 1024, height = 768))

//2.使用layer打印
p view.layer.bounds
或者
p (CGRect)[view bounds]这样

如何写一个参数不定的函数

先来看一下Foundation中创建一个数组的写法

NSArray *arr = [NSArray arrayWithObjects:id , nil];

这其中最后一个nil是告诉函数参数已经没了.我们自己在自定义的时候有时候也会遇到这样的需求,那么怎么定义一个这样的函数呢?这时候我们有一个概念叫做哨兵参数

C中,使用attribute((sentinel))可以创建一个哨兵参数

C中

在OC中,可以使用NS_REQUIRES_NIL_TERMINATION

@interface
-(void)functionAddtionWithParmater:(NSInteger)par,...NS_REQUIRES_NIL_TERMINATION;

@implementation
-(void)functionAddtionWithParmater:(NSInteger)par,...NS_REQUIRES_NIL_TERMINATION {
  va_list args;
  va_start(args, format);

  id arg = nil;
  while ((arg = va_arg(args,id))) {
  // Do your thing with arg here
  }

  va_end(args);

}

NULL/NSNull/nil/Nil的区别与联系

首先我们来看一下苹果文档中对于这几种概念的说明:

概念对比

1.NULL:由于OC来源于C,所以保留了这一标示,用0表示nothing的原始值,用NULL表示nothing的指针,所以我们可以这样理解0和NULL所表达的字面意思是完全一样的,只不过一个是值,一个是指针,适应不同的需求;

C represents nothing as 0 for primitive values, and NULL for pointers (which is equivalent to 0 in a pointer context).

2.nil:刚才我们说了NSNULL是C中的,表示nothing,那OC在这个基础上又增加了一个nil,OC是面向对象的一门语言,万物皆对象,nil就是用来表示nothing的一个对象,它与NSNULL的区别在于我们强调它是一个OC中的对象,两者的字面意思是一样的;

Objective-C builds on C’s representation of nothing by adding nil. nil is an object pointer to nothing. Although semantically distinct from NULL, they are technically equivalent to one another.

There’s Something About nil

当一个对象刚被alloc的时候,它的指针是指向0的(0x00),也就是说是从nil开始的;有一点要注意的是即便是nil,依然是可以接受消息的,在C++中可能会奔溃,但OC中会返回zero,这也更加说明了下面的写法没有必要:

// For example, this expression...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }

// ...can be simplified to:
if ([name isEqualToString:@"Steve"]) { ... }

3.NSNull:苹果官方对它的解释是:Something for Nothing很是形象.这是一个基于OC的framework定义的(Foundation框架中),它以一个类方法出现(+null),返回一个实实在在的对象,而并非是和nil一样表示nothing或者0值,尽管在我们看来他依然表示一个空的对象,但是技术上来说是不一样的;我们知道,在集合中是不允许插入一个不存在的值的,那如果我们有时候非要在集合中存储一个空值但是又不使程序报错呢?NSNull就是为了适应这样的需求的:

NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
mutableDictionary[@"someKey"] = [NSNull null];

4.Nil:Nil被定义为一个类的指针,表示一个nothing的类,我们并不常用,但是要知道;

参考文档:NSHipster


待续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • **2014真题Directions:Read the following text. Choose the be...
    又是夜半惊坐起阅读 9,437评论 0 23
  • 前段时间,《欢乐颂》受到无数人的追捧,一时间很多人写了剧情评论。而我总是习惯在电视剧的所有剧集都出来之后,我才开始...
    依恋射手阅读 544评论 0 1
  • 由此联想到工作当中所出现的各种各样的问题,也是同样的道理。假设将问题看做是子弹,在客户投诉后,解决问题之前,这中间...
    快乐茹雪阅读 198评论 0 0
  • 什么是亲人?亲人应该是跟你有血缘关系的人,亲人除了自己的爸妈,当然就是爸妈的亲人了,因为自己的爸妈那一代不是...
    何来何往16阅读 353评论 0 0