iOS开发经验(1)

目录:
  1. 在字符串查看指定字符串
  2. UILabel自适应
  3. 服务器数据处理
  4. copy解释
  5. 对象及可变字典赋值取值方法
  6. nil NSNULL NULL解释
  7. 字面量
  8. UILabel 黑线问题
  9. nullable和nonnull
1. 在Objective-C中怎么检查一个字符串中是否还有另外一个字符串.
  • 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自适应
  • UILabel不能设置竖直方向的排列布局,可以通过sizeToFit改变labelframe来实现曲线救国。
  • 适用于根据字体计算出文本单行的长度和高度(宽度和高度),注意是单行,首先来看单行文本的问题:对于单行文本来说,计算CGSize就比较简单了
CGSize size = [s.text sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:10]}];
  • 多行文本的显示:
    首先UILabelnumberOfLines设置为0,其次通过方法来计算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 来计算。
      嗯确实,这是个利器。其本上能正确返回字体的rect。但对于UITextView 似乎使用此方法计算出来的结果比实际显示的要小:UITextView在上下左右分别有一个8px的padding,需要将UITextView.contentSize.width减去16像素(左右的padding 2x8px)。同时返回的高度中再加上16像素(上下的padding),这样得到的才是UITextView真正适应内容的高度。如代码中
CGSizeMake(width -16.0, CGFLOAT_MAX)
return sizeToFit.height + 16.0。

UILable中则不用.

  • 通用(推荐)
CGSize sizeToFit = [textView sizeThatFits:CGSizeMake(width, MAXFLOAT)];
3.后台数据处理
  • 系统请求方法
    接受到的数据类型为NSData类型,需要json解析,解析后整个json字符串为字典类型,里面的数据类型可以为数组字典NSNumber(一般数据类型BOOL),字符串
NSDictionary *responsObj = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments   error:nil];
  • AFN请求方法
    通过指定接受到的数据格式为 text/json,可自动将数据解析
  • ** 通过以上两种方法获取数据并解析后。要对数据做容错处理。**
    通常我们以约定好的数据类型,定义对象去接受并使用数据,但要注意,有时候后台返回的并不是我们在客户端定义的数据类型,所以以下要做容错处理。
    由于数据造成app crash原因包括:获取的对象跟我们使用的方法不一致,比如字符串对象调用了字典的方法,空对象可以调用任何方法,这是系统设定的,不会crash
    所以一般判断步骤为:首先以约定好的数据类型接受后台数据,然后判断对象是否为空(nil,NULL),再判断是什么类型,特别是嵌套包含的数据,要一步步判断,切勿偷懒直接用字面量方法获取。
4. 三种方式 copy, mutableCopy, =
  • copy mutableCopy 统称为copy
    共同特点:对原对象改变,副本不改变;对副本改变,原对象不改变,互不影响。
    作用:在改变原有对象的时候,不会改变新对象的值
    原因在本小段末尾解释.

  • copy :
    创建的对象是不可变副本(如NSStringNSArrayNSDictionary)。
    不可变对象调用copy,原对象与副本对象地址一样,没有生成新对象,是浅拷贝;
    可变对象调用copy,原对象与副本对象地址不一样,生成了新的对象,是深拷贝。

  • mutableCopy:
    创建的对象是可变副本也是新对象(如NSMutableStringNSMutableArrayNSMutableDictionary)。
    不论是可变不可变对象调用mutableCopy方法,都属于深拷贝,生成一个新的对象,地址不一样。

  • =:
    同一个对象,改变任何一个,它俩都随之改变.

  • 解释改变其中一个另一个却不改变的原因:
    当对象为可变的对象,调用copy或者mutableCopy都会生成新的对象;
    当对象为不可变的时候,使用copy,不能对copy后的对象进行操作;使用mutableCopy,生成了新的对象.

    iOS开发经验(1)_第1张图片
    copy&mutableCopy.png

5. setvalue 与set object 字面量
  • setObject:ForKey: 是NSMutableDictionary特有的;setValue:ForKey:是KVC的主要方法;
  • setObject:ForKey:object对象不能为nil,不然会报错;key的参数只要是对象就可以,一般是NSString
  • setValue:ForKey:Value值可以为nil,此时会自动调用removeObject:forKey:方法;key的参数只能是NSString类型;
  • setValue:ForKey:是在NSObject对象中创建的,即所有的对象都有这个方法,可以用于任何类(方法调用者是对象的时候);
  • 注意:
    • [imageDictionary setObject:[NSNullnull] forKey:indexNumber]; [NSNull null]表示的是一个空对象,并不是nil,
    • 首先不可变字典可以调起setValue:forKey:,但不能真正的进行操作,这取决与不可变字典不可增删改的特性。
  • setValue:forKey:setValue:forKeyPath:
  • 动态设置: setValue:属性值 forKey:属性名(用于简单路径)、setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)
  • 动态读取: valueForKey:属性名valueForKeyPath:属性名(用于复合路径)
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: 来取值。
6. NSNull NULL nil
  • nil:指向oc中对象的空指针,针对对象。指针为空,不会发送消息的;return NO
    Nil:指向oc中类的空指针,针对类。
    NULL:指向其他类型的空指针,如一个c类型的内存指针,基本数据类型为空,基本类型。
    null,占位空对象,即野指针,指向垃圾内存,造成crash。抛出异常NSException
    NSNull:类名,它的实例就是null,空值对象。
        NSArray *arr1 = [NSNull null];
        NSArray * arr2 = nil;
        NSLog(@"%@", arr1);  
        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 只走这个+1
    }
        if ([arr2 isKindOfClass:[NSArray class]]) {
        }
        
        if (arr2 == NULL) {
        //arr2 走这个+1

        }
        if (arr2 == nil) {
        //arr2 走这个+2
        }
        if ([arr2 isKindOfClass:[NSNull class]]) {
        }
        [arr1 count]; //会crash。
        [arr2 count];//不会crash。
  • 僵尸对象:被释放的对象为僵尸对象, 已经被销毁的对象(不能再使用的对象).
    野指针: 指向僵尸对象(不可用内存)的指针 给野指针发消息会报EXC_BAD_ACCESS错误
    空指针: 没有指向存储空间的指针(里面存的是nil, 也就是0) 给空指针发消息是没有任何反应的,空指针是把指针为nil.
    为了避免野指针错误的常见办法: 在对象被销毁之后, 将指向对象的指针变为空指针
    接受null数据并打印并不会造成crash,造成crash的原因是发送消息
  • 服务器返回的数据,有null,还有niliOS是使用的OC语言, 跟C语言略有不同, 在OC中打印出(nill)两种情况是不同的, 的判断方法是
 - (id) setNoNull:(id)aValue{
    if (aValue == nil) {
        aValue = @"";//为null时,直接赋空
    } else if ((NSNull *)aValue == [NSNull null]) {
        aValue = @"";
        if ([aValue isEqual:nil]) {
            aValue = @"";
        }
    }
    return aValue;
}

既然它老出bug ,为什么还在oc里还有它的存在
NSNullnil以及NULL不同,因为它是一个实际的对象,而不是一个零值。
nil null 其实就是0
NSNullFoundation和其它框架中被广泛的使用,以解决如NSArrayNSDictionary之类的集合不能有nil值的缺陷。
你可以将NSNull理解为有效的将NULL或者nil值封装boxing,以达到在集合中使用它们的目的:

NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
mutableDictionary[@"someKey"] = [NSNull null]; // Sets value of NSNull singleton for `someKey`
NSLog(@"Keys: %@", [mutableDictionary allKeys]); // @[@"someKey"]
7. 字面量
  • 字面数值
    需要把整数、浮点数、布尔值封入到对象里。通常情况下会用到如下方法:
    NSNumber *number = [NSNumber numberWithInt:8];
    使用字面量语法后,不仅语法更简洁,还有很多好处。
    NSNumber *number = @(8);
    能够用以NSNumber实例表示的所有数据类型,都可以使用字面量语法。。。
  • 字面量数组
    数组的常用创建方法如下:
NSArray *array = [NSArray arrayWithObjects:@"obj1", @"obj2", nil];

而使用字面量语法则是:

NSArray *array = @[@"obj1", @"obj2"];

数组的取下标也有字面量语法:
NSString *obj = [array objectAtIndex:1];
使用字面量:
NSString *obj = array[1];
不过使用字面量数组时,要注意不要把nil加入到数组中,否则会抛出异常。

  • 字面量字典
    常用创建方式如下:
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"obj1", @"value1", @"obj2", @"value2", nil];
    而使用字面量语法,就比较简洁了。
    NSDictionary *dictionary = @{@"obj1": @"value1",
    @"obj1": @"value1"};
    字面量语法清晰表示出了,key和value的一一对应关系。但是与数组一样,字面量字典的value不能为nil,否则会出现异常。

  • 字面量可变数组与字典
    对于可变的数组与字典,同样可以使用自变量语法对自变量数组,字典进行操作。
    NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:@{@"obj1": @"value1", @"obj1": @"value1"}];mutableDictionary[@"obj3"] = @"value3";

  • ** 注意用字面量语法创建数组及字典时要注意,若数组元素对象中有nil,则会抛出异常**
    使用字面量语法创建出来的字符串、数组、字典对象都是不可变的(immutable)。若想要可变版本的对象,则需复制一份:

NSMutableArray *mutableArray = [@[@1, @2, @3, @4, @5]mutableCopy];
mutableArray[3] = @33;
NSMutableDictionary* mutableDic = [@{@"name":@"song",
                                 @"age":@"28",
                                  @"tel":@"1234567"}mutableCopy];
mutableDic[@"age"]=@"30";
  • 总结
  1. Foundation框架 是在iOS开发中 用到的最频繁的基础框架,它提供了几个最基本的类:NSStringNSNumberNSArrayNSDictionary. 在这个框架下,尽量使用对象字面量语法创建字符串, 数字, 数组和字典等.其他自定义的对象不可使用字面量。
  2. 在数组和字典中, 要使用关键字和索引做下标来获取数据
  3. 使用对象字面量语法时, 容器类里不可是nil, 否则运行时贵抛出异常.
8. UILabel 黑线问题

偶尔发现UILabel右边缘出现黑线,iPhone6P、6sP最为明显:
使用循环计算label尺寸, 循环创建label时有可能出现右边缘黑线的问题, 且有时在iPhone5s一下机型不会出现, 只在iPhone6以上出现 ,这是因为计算出得size可能的值会是30.31123323…… 这样的数。
猜想: 而像素值显示的时候不可能出现显示半个像素的情况, 那么不足一个像素的值就会被忽略掉, 在分辨率较低的机型上不会出现, 而分辨率较高的则不会忽略, 就出现了黑线。
解决方法
计算出来的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,这一新特性的核心是两个新的类型注释:nullable和nonnull。从字面上我们可以猜到,nullable表示对象可以是NULL或nil,而nonnull表示对象不应该为空。当我们不遵循这一规则时,编译器就会给出警告。
事实上,在任何可以使用const关键字的地方都可以使用nullable和nonnull,不过这两个关键字仅限于使用在指针类型上。而在方法的声明中,我们还可以使用不带下划线的nullable和nonnull,如下所示:

- (nullable id)itemWithName:(NSString * nonnull)name

在属性声明中,也增加了两个相应的特性,因此上例中的items属性可以如下声明:

@property (nonatomic, copy, nonnull) NSArray * items;

也可以用以下这种方式:

@property (nonatomic, copy) NSArray * __nonnull items;

如果需要每个属性或每个方法都去指定nonnull和nullable,是一件非常繁琐的事。苹果为了减轻我们的工作量,专门提供了两个宏:NS_ASSUME_NONNULL_BEGIN,NS_ASSUME_NONNULL_END。在这两个宏之间的代码,所有简单指针对象都被假定为nonnull,因此我们只需要去指定那些nullable的指针。

NS_ASSUME_NONNULL_BEGIN

@interface TestNullabilityClass ()
@property (nonatomic, copy) NSArray * items;
- (id)itemWithName:(nullable NSString *)name;
@end

NS_ASSUME_NONNULL_END

你可能感兴趣的:(iOS开发经验(1))