1. 系统NavigationBar的Title两行显示 & Label的多行富文本操作
- (void)replaceNavigationTitleView
{
// 初始化一个Label
UILabel *customTitleView = [[UILabel alloc] init];
customTitleView.width = 180;
customTitleView.height = 44;
customTitleView.numberOfLines = 0;
// 字符串赋值
NSString *name = @"Jaten";
NSString *detail = @"这是详细信息";
NSString *str = [NSString stringWithFormat:@"%@\n%@", name, detail];
// 设置段落风格
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
// 行间距
[paragraphStyle setLineSpacing:3.f];
// 此处会替换Label的NSTextAlignmentCenter,所以要在这里设置
[paragraphStyle setAlignment:NSTextAlignmentCenter];
// 富文本
NSMutableAttributedString * attrStr = [[NSMutableAttributedString alloc]initWithString:str];
[attrStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:[str rangeOfString:name]];
[attrStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:11] range:[str rangeOfString:detail]];
[attrStr addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:[str rangeOfString:detail]];
[attrStr addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [str length])];
customTitleView.attributedText = attrStr;
// 最后设置titleView
self.navigationItem.titleView = customTitleView;
}
2. atomic 和 non-atomic
两者的相同点:
系统都会自动生成getter/setter方法
两者的区别主要在于:
atomic:系统自动生成的getter/setter方法会进行加锁操作
nonatomic:系统自动生成的getter/setter方法不会进行加锁操作
用代码来表示:
atomic:
// mrc 环境
// implementation
@synthesize icon1 = _item1;
//set
-(void)setItem1:(UIImage *)item1
{
//同步代码块
@synchronized (self) {
if(_item1 != item1)
{
[_item1 release];
_item1 = [item1 retain];
}
}
}
//get
-(UIImage *)item1
{
UIImage *image = nil;
//同步代码块
@synchronized (self) {
image = [[_item1 retain] autorelease];
}
return image;
}
nonatomic:
// mrc 环境
// implementation
@synthesize icon = _item;
//set
-(void)setItem:(UIImage *)item
{
if(_item != item)
{
[_item release];
_item = [item retain];
}
}
//get
-(UIImage *)item
{
return _item;
}
虽然系统会为atomic声明的getter/setter方法加锁,但并不能保证程序的线程安全,原因是:
①调用getter
②调用setter
③调用setter
在setter存时,确实会不受其他getter/setter语句的影响,但是getter取时,由于无法保证线程的进行情况,可能取到的值有三种:未被②③改变的值;被②改变的值;被③改变的值。
结论:
所以atomic也不是线程安全的,我们还需要自己在用到多线程时谨慎处理。而在iOS设备上,nonatomic因为没有那么多复杂的加锁步骤,存取速度会比atomic快,再加上iOS设备的核心CPU数较少,atomic的加锁机制起到的作用很小,所以nonatomic还是相对atomic比较好用和高效的属性。
3. scrollView下拉深度埋点
最近业务中遇到了scrollView下拉深度埋点的需求,要求统计用户在浏览某个collectionView或tableView的时候下拉的深度。
需要埋点的页面要实现scrollView的scrollViewWillEndDragging:方法,在下拉列表并松开时,通过targetContentOffset来计算整个页面的下拉深度。
/*
下拉深度埋点
@param pageName 页面名称
@param scrollView 目标scrollView
@param targetContentOffsetY 即将滑动偏移量
@param paramDict 其他参数
*/
+ (void)sScanDeepStatisticsPageName:(NSString *)pageName scrollView:(UIScrollView *)scrollView targetContentOffsetY:(CGFloat)targetContentOffsetY otherParameters:(NSDictionary *)paramDict
{
// 取出此scrollView对应的最大浏览深度
NSInteger longestDeep = [[SPointManager sharedManager] getLongestScreenDeepWithPageName:pageName scrollViewTag:scrollView.tag];
// 判断是否比之前更深
NSInteger currentDeep = (scrollView.y + scrollView.height + contentOffsetY) / 1.0;
if (currentDeep == 0 || currentDeep <= longestDeep) {
return;
}
// 存入最大浏览深度
[[SPointManager sharedManager] saveLongestScreenDeepWithLongestScreenDeep:currentDeep PageName:pageName scrollViewTag:scrollView.tag];
// 通过接口发送至后台进行统计
}
以下是sPointManager类的代码,用于所有scrollView当前对应深度的存取
// .h文件
@interface SPointManager : NSObject
+ (SPointManager *)sharedManager;
// tag是为了区分某个页面具有多个scrollView
- (NSInteger)getLongestScreenDeepWithPageName:(NSString *)pageName scrollViewTag:(NSInteger)tag;
- (void)saveLongestScreenDeepWithLongestScreenDeep:(NSInteger)longestScreenDeep PageName:(NSString *)pageName scrollViewTag:(NSInteger)tag;
@end
// .m文件
@interface SPointManager ()
@property (nonatomic, strong) NSMutableDictionary *dict;
@end
@implementation SPointManager
+ (SPointManager *)sharedManager
{
static SPointManager *sPointManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sPointManager = [[self alloc] init];
});
return sPointManager;
}
- (NSInteger)getLongestScreenDeepWithPageName:(NSString *)pageName scrollViewTag:(NSInteger)tag
{
NSString *key = [NSString stringWithFormat:@"%@%ld", pageName, tag];
return [[self.dict objectForKey:key] integerValue];
}
- (void)saveLongestScreenDeepWithLongestScreenDeep:(NSInteger)longestScreenDeep PageName:(NSString *)pageName scrollViewTag:(NSInteger)tag
{
NSString *key = [NSString stringWithFormat:@"%@%ld", pageName, tag];
[self.dict setObject:[NSString stringWithFormat:@"%ld", longestScreenDeep] forKey:key];
}
- (NSMutableDictionary *)dict
{
if (!_dict) {
_dict = [NSMutableDictionary dictionary];
}
return _dict;
}
@end