目錄:
- 在字符串查看指定字符串
- UILabel自適應(yīng)
- 服務(wù)器數(shù)據(jù)處理
- copy解釋
- 對(duì)象及可變字典賦值取值方法
- nil NSNULL NULL解釋
- 字面量
- UILabel 黑線問(wèn)題
- nullable和nonnull
1. 在Objective-C中怎么檢查一個(gè)字符串中是否還有另外一個(gè)字符串.
- iOS8或
OS X Yosemite之后:
- (BOOL)containsString:(NSString *)str NS_AVAILABLE(10_10, 8_0);
之前:
NSString *string = @"hello bla bla";
if ([string rangeOfString:@"bla"].location == NSNotFound)
{
NSLog(@"string does not contain bla");
} else {
NSLog(@"string contains bla!");
}
2. UILabel自適應(yīng)
-
UILabel不能設(shè)置豎直方向的排列布局,可以通過(guò)sizeToFit改變label的frame來(lái)實(shí)現(xiàn)曲線救國(guó)。 - 適用于根據(jù)字體計(jì)算出文本單行的長(zhǎng)度和高度(寬度和高度),注意是單行,首先來(lái)看單行文本的問(wèn)題:對(duì)于單行文本來(lái)說(shuō),計(jì)算
CGSize就比較簡(jiǎn)單了
CGSize size = [s.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:10]}];
- 多行文本的顯示:
首先UILabel的numberOfLines設(shè)置為0,其次通過(guò)方法來(lái)計(jì)算CGSize,具體代碼如下:button.titleLabel亦如此
NSDictionary *attribute = @{NSFontAttributeName: font};
height = [text boundingRectWithSize:CGSizeMake(width, 0) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading | NSStringDrawingTruncatesLastVisibleLine attributes:attribute context:nil].size.height;
- UITextView多行文本的顯示:
-
boundingRectWithSize:options:attributes來(lái)計(jì)算。
嗯確實(shí),這是個(gè)利器。其本上能正確返回字體的rect。但對(duì)于UITextView 似乎使用此方法計(jì)算出來(lái)的結(jié)果比實(shí)際顯示的要小:UITextView在上下左右分別有一個(gè)8px的padding,需要將UITextView.contentSize.width減去16像素(左右的padding 2x8px)。同時(shí)返回的高度中再加上16像素(上下的padding),這樣得到的才是UITextView真正適應(yīng)內(nèi)容的高度。如代碼中
-
CGSizeMake(width -16.0, CGFLOAT_MAX)
return sizeToFit.height + 16.0。
UILable中則不用.
- 通用(推薦)
CGSize sizeToFit = [textView sizeThatFits:CGSizeMake(width, MAXFLOAT)];
3.后臺(tái)數(shù)據(jù)處理
- 系統(tǒng)請(qǐng)求方法
接受到的數(shù)據(jù)類型為NSData類型,需要json解析,解析后整個(gè)json字符串為字典類型,里面的數(shù)據(jù)類型可以為數(shù)組,字典,NSNumber(一般數(shù)據(jù)類型?BOOL),字符串。
NSDictionary *responsObj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
- AFN請(qǐng)求方法
通過(guò)指定接受到的數(shù)據(jù)格式為text/json,可自動(dòng)將數(shù)據(jù)解析 - ** 通過(guò)以上兩種方法獲取數(shù)據(jù)并解析后。要對(duì)數(shù)據(jù)做容錯(cuò)處理。**
通常我們以約定好的數(shù)據(jù)類型,定義對(duì)象去接受并使用數(shù)據(jù),但要注意,有時(shí)候后臺(tái)返回的并不是我們?cè)诳蛻舳硕x的數(shù)據(jù)類型,所以以下要做容錯(cuò)處理。
由于數(shù)據(jù)造成app crash原因包括:獲取的對(duì)象跟我們使用的方法不一致,比如字符串對(duì)象調(diào)用了字典的方法,空對(duì)象可以調(diào)用任何方法,這是系統(tǒng)設(shè)定的,不會(huì)crash。
所以一般判斷步驟為:首先以約定好的數(shù)據(jù)類型接受后臺(tái)數(shù)據(jù),然后判斷對(duì)象是否為空(nil,NULL),再判斷是什么類型,特別是嵌套包含的數(shù)據(jù),要一步步判斷,切勿偷懶直接用字面量方法獲取。
4. 三種方式 copy, mutableCopy, =
copymutableCopy統(tǒng)稱為copy
共同特點(diǎn):對(duì)原對(duì)象改變,副本不改變;對(duì)副本改變,原對(duì)象不改變,互不影響。
作用:在改變?cè)袑?duì)象的時(shí)候,不會(huì)改變新對(duì)象的值
原因在本小段末尾解釋.copy :
創(chuàng)建的對(duì)象是不可變副本(如NSString、NSArray、NSDictionary)。
不可變對(duì)象調(diào)用copy,原對(duì)象與副本對(duì)象地址一樣,沒(méi)有生成新對(duì)象,是淺拷貝;
可變對(duì)象調(diào)用copy,原對(duì)象與副本對(duì)象地址不一樣,生成了新的對(duì)象,是深拷貝。mutableCopy:
創(chuàng)建的對(duì)象是可變副本也是新對(duì)象(如NSMutableString、NSMutableArray、NSMutableDictionary)。
不論是可變不可變對(duì)象調(diào)用mutableCopy方法,都屬于深拷貝,生成一個(gè)新的對(duì)象,地址不一樣。=:
同一個(gè)對(duì)象,改變?nèi)魏我粋€(gè),它倆都隨之改變.-
解釋改變其中一個(gè)另一個(gè)卻不改變的原因:
當(dāng)對(duì)象為可變的對(duì)象,調(diào)用copy或者mutableCopy都會(huì)生成新的對(duì)象;
當(dāng)對(duì)象為不可變的時(shí)候,使用copy,不能對(duì)copy后的對(duì)象進(jìn)行操作;使用mutableCopy,生成了新的對(duì)象.
copy&mutableCopy.png
5. setvalue 與set object 字面量
-
setObject:ForKey:是NSMutableDictionary特有的;setValue:ForKey:是KVC的主要方法; -
setObject:ForKey:中object對(duì)象不能為nil,不然會(huì)報(bào)錯(cuò);key的參數(shù)只要是對(duì)象就可以,一般是NSString; -
setValue:ForKey:中Value值可以為nil,此時(shí)會(huì)自動(dòng)調(diào)用removeObject:forKey:方法;key的參數(shù)只能是NSString類型; -
setValue:ForKey:是在NSObject對(duì)象中創(chuàng)建的,即所有的對(duì)象都有這個(gè)方法,可以用于任何類(方法調(diào)用者是對(duì)象的時(shí)候); - 注意:
-
[imageDictionary setObject:[NSNullnull] forKey:indexNumber];[NSNull null]表示的是一個(gè)空對(duì)象,并不是nil, - 首先不可變字典可以調(diào)起
setValue:forKey:,但不能真正的進(jìn)行操作,這取決與不可變字典不可增刪改的特性。
-
-
setValue:forKey:與setValue:forKeyPath: - 動(dòng)態(tài)設(shè)置:
setValue:屬性值 forKey:屬性名(用于簡(jiǎn)單路徑)、setValue:屬性值 forKeyPath:屬性路徑(用于復(fù)合路徑,例如Person有一個(gè)Account類型的屬性,那么person.account就是一個(gè)復(fù)合屬性) - 動(dòng)態(tài)讀取:
valueForKey:屬性名、valueForKeyPath:屬性名(用于復(fù)合路徑)
Amodel *modelA = [[Amodel alloc]init];
SubAmodel *modela = [[SubAmodel alloc]init];
modela.str = @"qq.com";
modelA.submodel = modela;
NSLog(@"%@",modelA.submodel.str);
[modelA setValue:@"QQ.com" forKeyPath:@"submodel.str"];
NSLog(@"%@",modelA.submodel.str);
- 建議在
NSDictionary下只用objectForKey:來(lái)取值。
6. NSNull NULL nil
- nil:指向oc中對(duì)象的空指針,針對(duì)對(duì)象。指針為空,不會(huì)發(fā)送消息的;
return NO
Nil:指向oc中類的空指針,針對(duì)類。
NULL:指向其他類型的空指針,如一個(gè)c類型的內(nèi)存指針,基本數(shù)據(jù)類型為空,基本類型。
null,占位空對(duì)象,即野指針,指向垃圾內(nèi)存,造成crash。拋出異常NSException
NSNull:類名,它的實(shí)例就是null,空值對(duì)象。
NSArray *arr1 = [NSNull null];
NSArray * arr2 = nil;
NSLog(@"%@", arr1); <null>
NSLog(@"%@", arr2); (null)
NSLog(@"%p", arr1); 0x10cf4bd80
NSLog(@"%p", arr2); 0x0
if ([arr1 isKindOfClass:[NSArray class]]) {
}
if (arr1 == NULL) {
}
if (arr1 == nil) {
}
if ([arr1 isKindOfClass:[NSNull class]]) {
//arr1 只走這個(gè)+1
}
if ([arr2 isKindOfClass:[NSArray class]]) {
}
if (arr2 == NULL) {
//arr2 走這個(gè)+1
}
if (arr2 == nil) {
//arr2 走這個(gè)+2
}
if ([arr2 isKindOfClass:[NSNull class]]) {
}
[arr1 count]; //會(huì)crash。
[arr2 count];//不會(huì)crash。
-
僵尸對(duì)象:被釋放的對(duì)象為僵尸對(duì)象, 已經(jīng)被銷毀的對(duì)象(不能再使用的對(duì)象).
野指針: 指向僵尸對(duì)象(不可用內(nèi)存)的指針 給野指針發(fā)消息會(huì)報(bào)EXC_BAD_ACCESS錯(cuò)誤
空指針: 沒(méi)有指向存儲(chǔ)空間的指針(里面存的是nil, 也就是0) 給空指針發(fā)消息是沒(méi)有任何反應(yīng)的,空指針是把指針為nil.
為了避免野指針錯(cuò)誤的常見(jiàn)辦法: 在對(duì)象被銷毀之后, 將指向?qū)ο蟮闹羔樧優(yōu)榭罩羔?br> 接受null數(shù)據(jù)并打印并不會(huì)造成crash,造成crash的原因是發(fā)送消息 - 服務(wù)器返回的數(shù)據(jù),有
null,還有nil,iOS是使用的OC語(yǔ)言, 跟C語(yǔ)言略有不同, 在OC中打印出(nill)和<null>兩種情況是不同的,<null>的判斷方法是
- (id) setNoNull:(id)aValue{
if (aValue == nil) {
aValue = @"";//為null時(shí),直接賦空
} else if ((NSNull *)aValue == [NSNull null]) {
aValue = @"";
if ([aValue isEqual:nil]) {
aValue = @"";
}
}
return aValue;
}
既然它老出bug ,為什么還在oc里還有它的存在
NSNull與nil以及NULL不同,因?yàn)樗且粋€(gè)實(shí)際的對(duì)象,而不是一個(gè)零值。
nil null 其實(shí)就是0
NSNull在Foundation和其它框架中被廣泛的使用,以解決如NSArray和NSDictionary之類的集合不能有nil值的缺陷。
你可以將NSNull理解為有效的將NULL或者nil值封裝boxing,以達(dá)到在集合中使用它們的目的:
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
mutableDictionary[@"someKey"] = [NSNull null]; // Sets value of NSNull singleton for `someKey`
NSLog(@"Keys: %@", [mutableDictionary allKeys]); // @[@"someKey"]
7. 字面量
- 字面數(shù)值
需要把整數(shù)、浮點(diǎn)數(shù)、布爾值封入到對(duì)象里。通常情況下會(huì)用到如下方法:
NSNumber *number = [NSNumber numberWithInt:8];
使用字面量語(yǔ)法后,不僅語(yǔ)法更簡(jiǎn)潔,還有很多好處。
NSNumber *number = @(8);
能夠用以NSNumber實(shí)例表示的所有數(shù)據(jù)類型,都可以使用字面量語(yǔ)法。。。 - 字面量數(shù)組
數(shù)組的常用創(chuàng)建方法如下:
NSArray *array = [NSArray arrayWithObjects:@"obj1", @"obj2", nil];
而使用字面量語(yǔ)法則是:
NSArray *array = @[@"obj1", @"obj2"];
數(shù)組的取下標(biāo)也有字面量語(yǔ)法:
NSString *obj = [array objectAtIndex:1];
使用字面量:
NSString *obj = array[1];
不過(guò)使用字面量數(shù)組時(shí),要注意不要把nil加入到數(shù)組中,否則會(huì)拋出異常。
字面量字典
常用創(chuàng)建方式如下:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"obj1", @"value1", @"obj2", @"value2", nil];
而使用字面量語(yǔ)法,就比較簡(jiǎn)潔了。
NSDictionary *dictionary = @{@"obj1": @"value1",
@"obj1": @"value1"};
字面量語(yǔ)法清晰表示出了,key和value的一一對(duì)應(yīng)關(guān)系。但是與數(shù)組一樣,字面量字典的value不能為nil,否則會(huì)出現(xiàn)異常。字面量可變數(shù)組與字典
對(duì)于可變的數(shù)組與字典,同樣可以使用自變量語(yǔ)法對(duì)自變量數(shù)組,字典進(jìn)行操作。
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:@{@"obj1": @"value1", @"obj1": @"value1"}];mutableDictionary[@"obj3"] = @"value3";** 注意用字面量語(yǔ)法創(chuàng)建數(shù)組及字典時(shí)要注意,若數(shù)組元素對(duì)象中有nil,則會(huì)拋出異常**
使用字面量語(yǔ)法創(chuàng)建出來(lái)的字符串、數(shù)組、字典對(duì)象都是不可變的(immutable)。若想要可變版本的對(duì)象,則需復(fù)制一份:
NSMutableArray *mutableArray = [@[@1, @2, @3, @4, @5]mutableCopy];
mutableArray[3] = @33;
NSMutableDictionary* mutableDic = [@{@"name":@"song",
@"age":@"28",
@"tel":@"1234567"}mutableCopy];
mutableDic[@"age"]=@"30";
- 總結(jié)
-
Foundation框架 是在iOS開(kāi)發(fā)中 用到的最頻繁的基礎(chǔ)框架,它提供了幾個(gè)最基本的類:NSString、NSNumber、NSArray、NSDictionary. 在這個(gè)框架下,盡量使用對(duì)象字面量語(yǔ)法創(chuàng)建字符串, 數(shù)字, 數(shù)組和字典等.其他自定義的對(duì)象不可使用字面量。 - 在數(shù)組和字典中, 要使用關(guān)鍵字和索引做下標(biāo)來(lái)獲取數(shù)據(jù)
- 使用對(duì)象字面量語(yǔ)法時(shí), 容器類里不可是nil, 否則運(yùn)行時(shí)貴拋出異常.
8. UILabel 黑線問(wèn)題
偶爾發(fā)現(xiàn)UILabel右邊緣出現(xiàn)黑線,iPhone6P、6sP最為明顯:
使用循環(huán)計(jì)算label尺寸, 循環(huán)創(chuàng)建label時(shí)有可能出現(xiàn)右邊緣黑線的問(wèn)題, 且有時(shí)在iPhone5s一下機(jī)型不會(huì)出現(xiàn), 只在iPhone6以上出現(xiàn) ,這是因?yàn)橛?jì)算出得size可能的值會(huì)是30.31123323…… 這樣的數(shù)。
猜想: 而像素值顯示的時(shí)候不可能出現(xiàn)顯示半個(gè)像素的情況, 那么不足一個(gè)像素的值就會(huì)被忽略掉, 在分辨率較低的機(jī)型上不會(huì)出現(xiàn), 而分辨率較高的則不會(huì)忽略, 就出現(xiàn)了黑線。
解決方法
計(jì)算出來(lái)的UILabel尺寸,向上取整
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc]init];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping ;
[paragraphStyle setLineSpacing:4];
NSDictionary *attributes = @{NSFontAttributeName:kDesFont, NSParagraphStyleAttributeName:paragraphStyle.copy};
CGSize size = [text boundingRectWithSize:CGSizeMake(cellWidth, 0) options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil ].size ;
size.width = ceil(size.width);
size.height = ceil(height);
9. nullable和nonnull
Xcode 6.3新特性:Nullability Annotations,這一新特性的核心是兩個(gè)新的類型注釋:nullable和nonnull。從字面上我們可以猜到,nullable表示對(duì)象可以是NULL或nil,而nonnull表示對(duì)象不應(yīng)該為空。當(dāng)我們不遵循這一規(guī)則時(shí),編譯器就會(huì)給出警告。
事實(shí)上,在任何可以使用const關(guān)鍵字的地方都可以使用nullable和nonnull,不過(guò)這兩個(gè)關(guān)鍵字僅限于使用在指針類型上。而在方法的聲明中,我們還可以使用不帶下劃線的nullable和nonnull,如下所示:
- (nullable id)itemWithName:(NSString * nonnull)name
在屬性聲明中,也增加了兩個(gè)相應(yīng)的特性,因此上例中的items屬性可以如下聲明:
@property (nonatomic, copy, nonnull) NSArray * items;
也可以用以下這種方式:
@property (nonatomic, copy) NSArray * __nonnull items;
如果需要每個(gè)屬性或每個(gè)方法都去指定nonnull和nullable,是一件非常繁瑣的事。蘋果為了減輕我們的工作量,專門提供了兩個(gè)宏:NS_ASSUME_NONNULL_BEGIN,NS_ASSUME_NONNULL_END。在這兩個(gè)宏之間的代碼,所有簡(jiǎn)單指針對(duì)象都被假定為nonnull,因此我們只需要去指定那些nullable的指針。
NS_ASSUME_NONNULL_BEGIN
@interface TestNullabilityClass ()
@property (nonatomic, copy) NSArray * items;
- (id)itemWithName:(nullable NSString *)name;
@end
NS_ASSUME_NONNULL_END
