Kenny 肉桂的主页

记录自己的进步


  • 首页

  • 归档

  • 标签

  • 搜索
close

关于@property中NSString的copy-深入细节

发表于 2015-05-20   |   分类于 iOS Tips   |  

前几天和东盟君讨论关于在 @property(nonatomic,copy)NSString * string;中 copy的使用问题. 虽然自己很明白,见到NSString,果断用 copy,但是却说不出个道道.

今天偶尔在一片国外论坛的文章上看到了关于这个的内容(因为在pad上看的,具体地址没法引用了).所以简单记录一下.

因为类似 NSString这样的不可变父类,它们有可变的子类(比如 NSMutableString),那么就可能造成修改指针指向的结果,而这是我们不愿意看到的

是比较抽象的描述,要弄明白这段话,需要明确 copy 做了什么 ?

在官方的描述中: copy是复制一个对象,并强引用它.

那么开始解释一开始的话:

假设我有一个 Person 类,他有一个 name属性,它是NSString类型的.不可变对象对吧.

那么问题来了,下面的语法是成立的:

1
2
3
 NSMutableString * mutableString = [[NSMutableString alloc]initWithString:@"gg"];
//1
per.name = mutableString;

上面1处首先语法没有问题, NSString是 NSMutableString的父类.
然后这个时候,如果 name属性是 @property 是 strong的,
那么 per.name 和 mutableString 指向的是同一块内存区域,
那么,我就可以通过修改 mutableString来修改per.name了,而当初我们既然选择了 NSString,那么就是考虑到不会对其进行修改的.所以,这样违背了我们的初衷.

如果是copy,per.name在使用前会复制一份出来,这样使用的其实是它的副本,即使修改了mutableString也不会对per.name的本尊造成影响.

关于 copy 和 mutableCopy

现在我说的这两者是在代码中使用的时候,就是对象创建和赋值时候的.
苹果的设计是:

  • copy 拿到的永远是不可变对象
  • mutableCopy 拿到的是可变对象

为什么这样设计呢?

以上两者的调用者可能是 可变的或者不可变的,那么就会有四种组合,对于开发者去记忆四种组合是比较蹩脚的.所以干脆

  • 不管调用者类型是可变与否,copy到得就不可变
  • 不管调用者类型是可变与否,mutableCopy到得就是可变对象

关于创建可变类型

以前都是用类似 NSMutableString * string = [ NSMutableString string ];这样的方式创建,但是在和东盟君讨论的时候,打印了一下,发现 string的class是:

1
2
3
4
5
NSString * string = [NSString stringWithFormat:@"string"];
NSLog(@"string is %@",[string class]);

NSMutableString * mutableString = [NSMutableString string];
NSLog(@"mutable string is %@",[mutableString class]);

打印结果:

1
2
2015-05-20 10:36:43.549 TestNsstring[10993:1874316] string is __NSCFString
2015-05-20 10:36:43.550 TestNsstring[10993:1874316] mutable string is __NSCFString

究其原因, NSString是一个类簇,具体的实现都会找到合适的类,这个不用纠结了.

不久之后,在 iOS6 by Tutorial中一书中看到关于 [@[] mutableCopy] 和 [@{} mutableCopy] 这样的用法.

也符合 copy 和 mutableCopy 的准则

Tableview相关-iOS开发 Tips

发表于 2015-05-06   |   分类于 iOS Tips   |  
  • 在使用Tableview的时候,即使只是设置了几条数据,但是多余的部分还是会出现cell,就是出现了多余的分割线.

解决方案:

在TableViewController中添加一行代码即可

1
self.tableView.tableFooterView = [UIView alloc initWithFrame:CGRectZero];
  • 有时候用Tableview做布局的时候,我们并不希望它是可以滚动的.所以,可以使用如下代码禁止滚动
1
self.tableView.scrollEnabled = NO ;
  • 设置不让cell选中时高亮
1
self.selectionStyle = UITableViewCellSelectionStyleNone;
  • 去掉表格之间的分割线
1
dataTableview.separatorStyle = UITableViewCellSeparatorStyleNone;

管理代码片段

发表于 2015-05-05   |   分类于 环境、配置相关   |  

介绍

Xcode 界面的右下角 , 可以通过快捷键 Cmd+Ctrl+Opt+2 调出来, 代码片段是一些代码的模板, 对一些常见的编程模式 ,Xcode 都将这些代码抽象成模板放到代码片段中,使用的时候,只需要按快捷键,就可以把模板的内容填到代码中.

例如苹果引入两 GCD 之后,我们需要一个延时的操作,只需要在 Xcode 中键入 dispatch ,就可以看到 Xcode 中弹出一个上下文菜单, 第一个选项就是相应的代码片段.

Xcode代码片段的管理

那么如何自定义代码片段呢? 相当简单,当你觉得某段代码很有用,可以当做模板的时候,将其整体选中,拖动到 Xcode 右下角的代码片段区域中即可. Xcode 会自动帮你创建的代码片段. 之后可以单机该代码片段,在弹出的界面中选择 “Edit”,即可为此代码片段设置快捷键等信息.

可以直接敲代码,然后拖到右下角

如果有些地方想让用户替换掉,可以用 <#被替换的内容#>的格式 .这样在代码片段被使用后,焦点会自动移动到该处,你只需要连贯的键入替换后的内容即可.

可以使用git管理代码片段.

代码片段默认目录是:

cd ~/Library/Developer/Xcode/UserData/CodeSnippets/

可以对该目录使用 git ,那么就能随时使用自己的代码片段了.

其他管理工具

其他类似功能的还有 Dash 和 SnippetsLib ,它们两者的优势是支持任意语言.

但是如果针对iOS开发 ,Xcode默认的代码片段还是首选 .

蓝牙扫描的坑

发表于 2015-05-02   |   分类于 坑   |  

今天公司有同事要求手机连接一个蓝牙设备, 要求是手机自动连接过去.简单翻了一下Apple的文档还找了几个网页,觉得了然于心了.于是先写出了进行扫描的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
@interface ViewController () <CBCentralManagerDelegate> {
CBCentralManager *bleManager_;
}
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
bleManager_ = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[bleManager_ scanForPeripheralsWithServices:nil options:nil];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[bleManager_ stopScan];
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
NSLog( @"%@", central );
switch ( central.state ) {
case CBCentralManagerStateUnknown: {
NSLog( @"%@", @"CBCentralManagerStateUnknown" );
break;
}
case CBCentralManagerStateResetting: {
NSLog( @"%@", @"CBCentralManagerStateResetting" );
break;
}
case CBCentralManagerStateUnsupported: {
NSLog( @"%@", @"CBCentralManagerStateUnsupported" );
break;
}
case CBCentralManagerStateUnauthorized: {
NSLog( @"%@", @"CBCentralManagerStateUnauthorized" );
break;
}
case CBCentralManagerStatePoweredOff: {
NSLog( @"%@", @"CBCentralManagerStatePoweredOff" );
break;
}
case CBCentralManagerStatePoweredOn: {
NSLog( @"%@", @"CBCentralManagerStatePoweredOn" );

break;
}
}
}

- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary<NSString *, id> *)advertisementData
RSSI:(NSNumber *)RSSI {
NSLog( @"BLE found %@", peripheral.name );
}

- (void)centralManager:(CBCentralManager *)central
didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog( @"BLE connected %@", peripheral.name );
}

- (void)centralManager:(CBCentralManager *)central
didFailToConnectPeripheral:(CBPeripheral *)peripheral
error:(nullable NSError *)error {
NSLog( @"BLE connected %@ faild %@", peripheral.name, error );
}

@end

真机运行, 发现打印了 CBCentralManagerStatePoweredOn ,但是之后就没有后文了. 发现外设的代理方法没有调用.但是直接通过手机进行扫描,能够发现设备.反复尝试,还是没有得到预期的结果.

后来想到,自己尝试在手机上反复开关蓝牙让列表刷新,注意到蓝牙开关是有一定时间的.结合自己在代码中:

1
2
bleManager_ = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[bleManager_ scanForPeripheralsWithServices:nil options:nil];

初始化了直接就开始扫描, 可能是由于蓝牙的Manager还没有准备好吧,于是尝试修改这个开始扫描到判定Manager的状态为PowerOn中:

1
2
3
4
5
6
case CBCentralManagerStatePoweredOn: {
NSLog( @"%@", @"CBCentralManagerStatePoweredOn" );
[bleManager_ scanForPeripheralsWithServices:nil options:nil];

break;
}

再进行打印,发现终于出现了各个外设了.

MJExtention 对不规范 JSON 解析的一个测试

发表于 2015-04-18   |   分类于 iOS Tips   |  

Context

今天受 MJ 老师吩咐,测试 MJExtension 对于不规范的 JSON 的解析情况.特记录于此

说明几点

何为不规范

我说的不规则指的是有一定容错能力,但是前提还是 JSON,弄些乱七八糟的字符串就没有意义了哈.比如说,这次我想测试的是前一段事件遇到的一个小问题:服务端返回的是类似这样的一个结果:

为了展现,截图是规范的 JSON,服务端给我的实际数据是:
两个箭头指向处还有 " .

换句话说,他是严格执行的: "键":"无论啥类型" . 网上大多数的所谓的 JSON 格式校验工具认为这种格式是 okay 的,但是它的问题是,没法继续”钻下去” ,这里就是我所说的 “不规范”.
说到这里,推荐个地址 在线校验,这个不仅仅是校验,还有格式化功能.支持按层级折叠和展开.

阅读全文 »

博客成长记

发表于 2015-04-15   |   分类于 主页维护记录   |  

加入评论功能

2015-04-15 12:59:49

  1. 使用微博或者其他帐号登录多说,建立自己的一个帐号,同时拿到通用代码.

  2. 取消HEXO博客根目录中的 _config.yml 中 disqus_shortname: ,暂时不用这个功能,直接永久开启多说评论。

  3. 修改主题目录下面的(我的是 /themes/jacman/_config.ym ) _config.yml 中的

1
2
#### Comment
duoshuo_shortname: guiqingblog ## e.g. wuchong your duoshuo short name.

如果没有请添加.

  1. 修改 themes\XXX\layout_partial\article.ejs
    在最后加上下面的代码:
1
2
3
<% if(!index){ %>
<%- partial('comment') %>
<% } %>
  1. 修改 themes/jacman/layout/_partial/post/comment.ejs 为你通用代码的 js 部分,如果没有这个文件请新建.

最终效果:

参考网址:

http://gpio.me/hexo-duoshuo.html
http://duoshuo.com

1…91011…13
桂庆

桂庆

Kenny 肉桂的主页 记录自己的进步

75 日志
17 分类
23 标签
RSS
微博
© 2013 - 2017 桂庆
由 Hexo 强力驱动
主题 - NexT.Mist