此篇文章會(huì)不斷更新,添加一些自己項(xiàng)目中發(fā)現(xiàn)的小知識(shí)點(diǎn),與君共勉.
文章同步在 個(gè)人主頁,閱讀體驗(yàn)可能好點(diǎn)~
==目錄==
修改UISearchBar的cancel按鈕為”取消”
Present一個(gè)可以調(diào)整大小的視圖
iOS 8下設(shè)置cell的分割線縮進(jìn)separatorInset
weakSelf, strongSelf寫法
關(guān)于iOS9的定位
iOS開發(fā)中的四舍五入、進(jìn)位、摸位 方法
scrollView中有兩個(gè)協(xié)議方法,之前一直沒在意,今天用的時(shí)候,發(fā)現(xiàn)有問題了,挺有意思的;
[NSDate date]返回年份錯(cuò)誤
將視圖添加到導(dǎo)航欄之上
Xcode調(diào)試技巧之lldb中導(dǎo)入U(xiǎn)IKit
如何寫一個(gè)參數(shù)不定的函數(shù)
NULL/NSNull/nil/Nil的區(qū)別與聯(lián)系
修改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一個(gè)可以調(diào)整大小的視圖
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);
**延伸:關(guān)于模態(tài)視圖的一些屬性 **
** -彈出風(fēng)格UIModalPresentationStyle**
1.UIModalPresentationFullScreen:
充滿全屏,對(duì)于IOS7以后版本,如果彈出視圖控制器的wantsFullScreenLayout設(shè)置為YES的,則會(huì)填充到狀態(tài)欄下邊,否則不會(huì)填充到狀態(tài)欄之下。
2.UIModalPresentationPageSheet:
高度和當(dāng)前屏幕高度相同,寬度和豎屏模式下屏幕寬度相同,剩余未覆蓋區(qū)域?qū)?huì)變暗并阻止用戶點(diǎn)擊,這種彈出模式下,豎屏?xí)r跟 UIModalPresentationFullScreen的效果一樣,橫屏?xí)r候兩邊則會(huì)留下變暗的區(qū)域。
++ UIModalPresentationFormSheet風(fēng)格的模態(tài)窗口,它的大小是可以進(jìn)行調(diào)整的,而且它會(huì)隨著鍵盤的彈起進(jìn)行移動(dòng)++
3.UIModalPresentationFormSheet:
高度和寬度均會(huì)小于屏幕尺寸,居中顯示,四周留下變暗區(qū)域.
4.UIModalPresentationCurrentContext:
彈出視圖控制器的彈出方式和它的父VC的方式相同.
說明:對(duì)于iphone,只有UIModalPresentationFullScreen一種風(fēng)格,即使設(shè)置成其它風(fēng)格也沒起作用
** -彈出時(shí)的動(dòng)畫風(fēng)格UIModalTransitionStyle**
1.UIModalTransitionStyleCoverVertical // 底部滑入。
2.UIModalTransitionStyleFlipHorizontal // 水平翻轉(zhuǎn)。
3.UIModalTransitionStyleCrossDissolve // 交叉溶解。
4.UIModalTransitionStylePartialCurl // 翻頁。
iOS 8下設(shè)置cell的分割線縮進(jìn)separatorInset
iOS 7下, 想要設(shè)置cell的分割線縮進(jìn)為0,在iOS7中只用簡單的設(shè)置cell的separatorInset = UIEdgeInsetZero;
iOS 8下, 在iOS8下,上面的方法就不行啦,經(jīng)過查閱資料, 終于在stackoverflow上查到了詳細(xì)的說明,源地址戳這里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.
什么意思呢,就讓我這個(gè)英語四級(jí)的戰(zhàn)五渣來試著翻譯一下吧.
iOS8中,新加入了一個(gè)屬性:preservesSuperviewLayoutMargins,吶,這個(gè)屬性的加入,可以避免你的cell的外邊繼承自你的tableView,當(dāng)你設(shè)置這個(gè)屬性的時(shí)候,你可以自由的設(shè)置你的cell的外邊距,而不必?fù)?dān)心tableView和cell兩者的相互影響.(翻譯的好渣,你們自己去看英文吧...)
代碼實(shí)現(xiàn)
//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;
關(guān)于iOS9的定位
如果你的APP不適配iOS9,就不能偷偷在后臺(tái)定位,iOS9中的CLLocation新增了一個(gè)屬性:allowsBackgroundLocationUpdates,而且默認(rèn)值為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開發(fā)中的四舍五入、進(jìn)位、摸位 方法
1.四舍五入比較簡單:
double number;
float result1 = rounding(number, 2);//保留兩位
int result2 = (int)roundf(number);
2.進(jìn)位方法:
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中有兩個(gè)協(xié)議方法,之前一直沒在意,今天用的時(shí)候,發(fā)現(xiàn)有問題了,挺有意思的;
//本來想在tableView停止?jié)L動(dòng)之后做一些事情,就調(diào)用了方法①,可是發(fā)現(xiàn)不會(huì)執(zhí)行,就看了一下文檔,恍然大悟!
①-scrollViewDidEndScrollingAnimation: //is called when a programmatic-generated scroll finishes.意思就是這個(gè)事系統(tǒng)級(jí)的動(dòng)畫執(zhí)行完畢觸發(fā)的
②-scrollViewDidEndDecelerating: //is called when a user-swipe scroll finishes.這個(gè)是用戶自己滑動(dòng)之后停止觸發(fā)的
還有一點(diǎn)自己之前也沒有注意到,** 有時(shí)候我們在拖拽的時(shí)候,手慢慢松開,這時(shí)候scrollView是跟隨拖拽立即停止,注意這時(shí)候scrollViewDidEndScroll是不會(huì)觸發(fā)的,我們要調(diào)用③**
③- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate:
// called on finger up if the user dragged. decelerate is true if it will continue moving afterwards
//這個(gè)方法就適用于拖拽停止的場景,可以利用參數(shù)decelerate來作為判斷是否拖拽之后停止OR繼續(xù)減速滾動(dòng)了;
[NSDate date]返回年份錯(cuò)誤
NSDate *date = [NSDate date];
NSDateFormatter *formater = [[NSDateFormatter alloc] init];
[formater setDateFormat:@"YYYY-MM-dd"];
NSString *tempStr = [formater stringFromDate:date];
假如現(xiàn)在的時(shí)間是2015.12.28,以上這段代碼返回值是什么?
你估計(jì)有一些人心里會(huì)想,這個(gè)二貨,這么簡單的問題簡直是在侮辱我的智商啊!然后脫口而出:2015-12-28;
但是我想說的是,一開始我也這么想的,而且郁悶了很久,沒錯(cuò),返回的是2016-12-28,年份大了一年,如果想返回正確的時(shí)間,你需要把YYYY改成yyyy...雖然這個(gè)錯(cuò)誤改正過來了,但是很納悶,為什么會(huì)返回給我個(gè)年份大于一年的時(shí)間呢?查閱了很多資料,最后得出了答案 - ISO 8601.國際數(shù)據(jù)存儲(chǔ)交換標(biāo)準(zhǔn),叫做week year,以星期來規(guī)劃年份,關(guān)于這個(gè)怎么個(gè)規(guī)劃法,我就不說了,有點(diǎn)晦澀難理解,這里只說一點(diǎn):
這個(gè)標(biāo)準(zhǔn)日歷日期中,一年當(dāng)中的最后一周有以下兩個(gè)要求:
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號(hào)的那個(gè)周日,如果31號(hào)是周一周二周三或者周四,那它就是下一年的第一周,如果是周五周六周日,那它是當(dāng)年的最后一周
再回過頭來看看我這個(gè)問題,還真是趕得巧,正好28號(hào)是周一,意味著這要算到下一年的第一周了,所以返回的年份是2016,這里也要慶幸出問題了,漲了姿勢了~
將視圖添加到導(dǎo)航欄之上
如果你有一個(gè)子視圖subVC(繼承自UIVIewController),它只是作為臨時(shí)出現(xiàn),把它添加到當(dāng)前控制器CorrentViewConteoller之上并且要覆蓋CorrentVC的導(dǎo)航欄,改如何添加呢?
這里介紹幾種方法以及說明一下優(yōu)缺點(diǎn):
//第一種:直接添加到keyWindow上
UIWIndow *keyWindow = [[[UIApplication shareApplication] delegate] window];
[keyWindow addSubView:subVC.view];
優(yōu)缺點(diǎn):簡單直接暴力,直接添加到最頂層的window上,但是有一個(gè)問題:首先,它會(huì)一直在最頂層,如果你需要present一個(gè)視圖,而且當(dāng)前subVC不能立即釋放,那么在轉(zhuǎn)場的時(shí)候你會(huì)發(fā)現(xiàn)這個(gè)煩人的subVC總是會(huì)出現(xiàn)在你的頂層視圖;其次,這種方法添加的subVC,在屏幕發(fā)生旋轉(zhuǎn)的時(shí)候,它并不會(huì)跟隨旋轉(zhuǎn),自己在項(xiàng)目中就遇到過:程序啟動(dòng)的時(shí)候就去搜索藍(lán)牙,當(dāng)前屏幕還是豎屏,隨后馬上轉(zhuǎn)為橫屏,這時(shí)候彈出的提示框還是豎屏狀態(tài)下的...當(dāng)然這種也是有解決方案的:查看
//第二種:隱藏導(dǎo)航欄
[currentVC.navigationController.navigationBar setNavigationBarHidder:YES animation:YES];
[currentVC.view addSubView:subVC];
[currentVC addChildViewController:subVC];
優(yōu)缺點(diǎn):也比較簡單直接,但是可能會(huì)對(duì)你的correntVC產(chǎn)生不好的影響:導(dǎo)致你的correntVC向上偏移64個(gè)單位,當(dāng)然你可以通過重新修改它的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];//下面會(huì)說為何要實(shí)現(xiàn)這個(gè)方法
[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];
}];
優(yōu)缺點(diǎn):對(duì)于subVC的界面布局,需要在init方法中設(shè)置完成,同時(shí)不要忘了手動(dòng)設(shè)置frame
//第四種:設(shè)置NavigationBar的zPosition達(dá)到目的
直接添加到當(dāng)前View上,不需要設(shè)置導(dǎo)航欄隱藏,而是直接設(shè)置導(dǎo)航欄的zPosition為-1,默認(rèn)為0,這樣,我們的subVC就可以完整的顯示了;
[self.view addSubView:subVC.view];
self.navigationController.navigationBar.layer.zPosition = -1;
[self addChildViewController:subVC];
優(yōu)缺點(diǎn):你可能注意到了,這個(gè)zPosition屬性是在layer層上的,那說明什么呢?說明我們只是在渲染層面將navigation這一層隱藏了,但是它的觸摸事件還是存在的,是會(huì)截?cái)鄐ubVC在這個(gè)地方的響應(yīng)的,所以這個(gè)方法并不好...
意外發(fā)現(xiàn)之延伸:假如我們上文提到的subVC是一個(gè)繼承自UINavigationController的子視圖的話,你想把它通過addSubView的方法添加到correntVC上,用來管理后面的一些視圖tempVC,那么會(huì)有一個(gè)問題:在push或者pop的過程中,子視圖(tempVC)的viewWillAppera,willDidAppera,viewWillDisappera等方法都不會(huì)被吊起,你需要在navigationVC的容器中手動(dòng)吊起這里有一篇說明
_ _ _
>####Xcode調(diào)試技巧之lldb中導(dǎo)入U(xiǎn)IKit
有時(shí)候想在斷點(diǎn)的時(shí)候打印一下UIView的bounds,但是會(huì)出現(xiàn)這樣的提示:
```language
(lldb) p [self bounds]
error: 'bounds' has unknown return type; cast the call to its declared return type
error: 1 errors parsing expression
這時(shí)候有計(jì)重解決辦法:
//1.導(dǎo)入U(xiǎn)Ikit或者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]這樣
如何寫一個(gè)參數(shù)不定的函數(shù)
先來看一下Foundation中創(chuàng)建一個(gè)數(shù)組的寫法
NSArray *arr = [NSArray arrayWithObjects:id , nil];
這其中最后一個(gè)nil是告訴函數(shù)參數(shù)已經(jīng)沒了.我們自己在自定義的時(shí)候有時(shí)候也會(huì)遇到這樣的需求,那么怎么定義一個(gè)這樣的函數(shù)呢?這時(shí)候我們有一個(gè)概念叫做哨兵參數(shù)
C中,使用attribute((sentinel))可以創(chuàng)建一個(gè)哨兵參數(shù)

在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的區(qū)別與聯(lián)系
首先我們來看一下蘋果文檔中對(duì)于這幾種概念的說明:

1.NULL:由于OC來源于C,所以保留了這一標(biāo)示,用0表示nothing的原始值,用NULL表示nothing的指針,所以我們可以這樣理解0和NULL所表達(dá)的字面意思是完全一樣的,只不過一個(gè)是值,一個(gè)是指針,適應(yīng)不同的需求;
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在這個(gè)基礎(chǔ)上又增加了一個(gè)nil,OC是面向?qū)ο蟮囊婚T語言,萬物皆對(duì)象,nil就是用來表示nothing的一個(gè)對(duì)象,它與NSNULL的區(qū)別在于我們強(qiáng)調(diào)它是一個(gè)OC中的對(duì)象,兩者的字面意思是一樣的;
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
當(dāng)一個(gè)對(duì)象剛被alloc的時(shí)候,它的指針是指向0的(0x00),也就是說是從nil開始的;有一點(diǎn)要注意的是即便是nil,依然是可以接受消息的,在C++中可能會(huì)奔潰,但OC中會(huì)返回zero,這也更加說明了下面的寫法沒有必要:
// For example, this expression...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }
// ...can be simplified to:
if ([name isEqualToString:@"Steve"]) { ... }
3.NSNull:蘋果官方對(duì)它的解釋是:Something for Nothing很是形象.這是一個(gè)基于OC的framework定義的(Foundation框架中),它以一個(gè)類方法出現(xiàn)(+null),返回一個(gè)實(shí)實(shí)在在的對(duì)象,而并非是和nil一樣表示nothing或者0值,盡管在我們看來他依然表示一個(gè)空的對(duì)象,但是技術(shù)上來說是不一樣的;我們知道,在集合中是不允許插入一個(gè)不存在的值的,那如果我們有時(shí)候非要在集合中存儲(chǔ)一個(gè)空值但是又不使程序報(bào)錯(cuò)呢?NSNull就是為了適應(yīng)這樣的需求的:
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
mutableDictionary[@"someKey"] = [NSNull null];
4.Nil:Nil被定義為一個(gè)類的指針,表示一個(gè)nothing的類,我們并不常用,但是要知道;
參考文檔:NSHipster
待續(xù)