使用UIDataDetectorTypes自动检测电话、网址和邮箱

 

webView.dataDetectorTypes = UIDataDetectorTypePhoneNumber;//自动检测网页上的电话号码,单击可以拨打

接下来我们来简单讲一下,使用UIDataDetectorTypes自动检测电话、网址和邮箱。我们先来看看UIDataDetectorTypes有哪些枚举值。

UIDataDetectorTypes的枚举值

typedef NS_OPTIONS(NSUInteger, UIDataDetectorTypes) {
    UIDataDetectorTypePhoneNumber   = 1 << 0,          // Phone number detection
    UIDataDetectorTypeLink          = 1 << 1,          // URL detection    
#if __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
    UIDataDetectorTypeAddress       = 1 << 2,          // Street address detection
    UIDataDetectorTypeCalendarEvent = 1 << 3,          // Event detection
#endif    

    UIDataDetectorTypeNone          = 0,               // No detection at all
    UIDataDetectorTypeAll           = NSUIntegerMax    // All types
};

NS_OPTIONS一般用来定义位移相关操作的枚举值。UIDataDetectorTypeAddress,UIDataDetectorTypeCalendarEvent不在我们考虑的范围了。

UIWebView有dataDetectorTypes属性,UITextView也有dataDetectorTypes属性。我们来UITextView来举例。

创建UITextView

UITextView *textView = [[UITextView alloc] initWithFrame:self.view.bounds];
textView.font = [UIFont systemFontOfSize:20];
textView.editable = NO;
textView.text = @"\r\n我的手机号不是: 13888888888 \r\n\r\n"
"我的博客刚刚在线网址: www.xxxxxx.com \r\n\r\n"
"我的邮箱: worldligang@163.com \r\n\r\n";
[self.view addSubview:textView];

运行起来看一下:

UIDataDetectorTypes1

可以看出来就是一个简单的文本,电话号码,网址和邮箱都没有检测出来。下面我们来看看dataDetectorTypes作用。

UIDataDetectorTypePhoneNumber检测电话

textView.dataDetectorTypes = UIDataDetectorTypePhoneNumber;

设置textView.dataDetectorTypes的属性,即可检测文本中的电话。效果如下所示:

UIDataDetectorTypes2

UIDataDetectorTypeLink检测网址和邮箱

textView.dataDetectorTypes = UIDataDetectorTypeLink;

UIDataDetectorTypeLink检测网址和邮箱的。点击网址会跳转到相应的网页,点击邮箱可以调用系统的发邮件。

UIDataDetectorTypes3

UIDataDetectorTypeAll检测电话、网址和邮箱

textView.dataDetectorTypes = UIDataDetectorTypeAll;

UIDataDetectorTypeAll可以检测检测电话、网址和邮箱。效果如下:

UIDataDetectorTypes4

专门写了一个iOSStrongDemo以后都在这个iOSStrongDemo里面更新内容。下载地址:iOSStrongDemo

UIWebView用法详解及代码分享

JUL 8TH, 2015 11:52 PM

今天加入一个QQ群,也算是一个圈子,群主的要求是满足他的三个条件。经过与群主的沟通,终于得到通过,顺利加入。

群主是一个93年的小伙,而且是河南的老乡。没想到小伙子这么有号召力。我也是偶然在我的空间发现他的,看他每天发的文章,还挺有意思。

90后的小伙子都这么厉害了,有什么理由不努力奋斗呢!多加入以下圈子,认识一下身边的牛人。说不定会有意外的收获。

今天我们来详细UIWebView用法。UIWebView是iOS内置的浏览器控件,可以浏览网页、打开文档等 能够加载html/htm、pdf、docx、txt等格式的文件.

用UIWebView我们就可以做一个简易的浏览器。效果如下:

1

创建UIWebView

首先创建UIWebView,这个不难,设置frame,然后添加到self.view上即可:

UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
webView.scalesPageToFit = YES;//自动对页面进行缩放以适应屏幕
[self.view addSubview:webView];

UIWebView加载网络地址

用UIWebView来加载网络地址,那我的博客:http://www.superqq.com 来举例。代码如下:

NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.superqq.com"]];
[self.view addSubview:webView];
[webView loadRequest:request];

UIWebView加载本地资源

通过NSURLRequest加载

NSString *path = [[NSBundle mainBundle] pathForResource:@"swift" ofType:@"html"];
NSURL* url = [NSURL   fileURLWithPath:path];//创建URL
NSURLRequest* request = [NSURLRequest requestWithURL:url];//创建NSURLRequest
[webView loadRequest:request];//加载

通过NSString加载

UIWebView 还支持将一个NSString对象作为源来加载。你可以为其提供一个基础URL,来指导UIWebView对象如何跟随链接和加载远程资源:

NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
NSString *htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:htmlString baseURL:[NSURL URLWithString:path]];

自动检测电话

设置这个属性,如果在加载的网页中遇到电话号码,直接单击就可以拨打,非常方便:

webView.dataDetectorTypes = UIDataDetectorTypePhoneNumber;//自动检测网页上的电话号码,单击可以拨打

设置代理和代理方法

UIWebView有五个代理方法,我们可以在不同的代理方法中,完成不同的需求。

//设置代理
webView.delegate = self;

//代理方法
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    //返回YES,进行加载。通过UIWebViewNavigationType可以得到请求发起的原因
    return YES;
}

- (void)webViewDidStartLoad:(UIWebView *)webView
{
    //开始加载,可以加上风火轮(也叫菊花)
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    //完成加载
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    //加载出错
}

创建加载他、停止、后退、前进按钮

创建四个按钮,分别是加载按钮、停止按钮、返回按钮、前进按钮:

NSArray *array = [NSArray arrayWithObjects:@"加载",@"停止",@"返回",@"前进", nil];
    int far = (SCREEN.width - 200)/5;
    for (int i = 0; i < array.count; i++) {
        UIButton *button = [[UIButton alloc] init];
        button.frame = CGRectMake( (i + 1) * far + 50 * i, SCREEN.height - 60, 50, 40);
        button.tag = 200 + i;
        [button addTarget:self action:@selector(actionClick:) forControlEvents:UIControlEventTouchUpInside];
        [button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
        [button setBackgroundColor:[UIColor orangeColor]];
        [button setTitle:array[i] forState:UIControlStateNormal];
        [self.view addSubview:button];
    }

前进后退

给四个按钮绑定事件,根据tag值来区分每一个点击事件:

- (void)actionClick:(UIButton *)button
{
    switch (button.tag) {
        case 200:
        {
            [self.webView reload];//加载
        }
            break;
        case 201:
        {
            [self.webView stopLoading];//停止加载
        }
            break;
        case 202:
        {
            [self.webView goBack];//返回
        }
            break;
        case 203:
        {
            [self.webView goForward];//前进
        }
            break;
        default:
            break;
    }
}

大功告成,再来看看效果:

2

以上分享的内容我做了一个demo,需要的话可以点击这里下载:UIWebView用法详解

NSLocale的重要性和用法简介

JUL 7TH, 2015 10:33 PM

股票还在努力的往下跌,怎么办呢?我这真是杞人忧天啊。谁说我不着急呢?我的模拟炒股都亏的过半了吧。你想想那些真真炒股的人该有多担心。

罢了罢了,我还是滚去撸代码,消灭bug吧。

上百万APP你用过几个?

随着iPhone的日趋强盛,随着AppStore的不断壮大,海量的应用如潮水般涌来。据统计AppStore上的应用早已过120万,Google Play Store更是超于AppStore,达到150万。

知道120万、150万是什么概念吗?人生不过短短两三万天。也就是说,如果你一天用一个APP的话,AppStore够你用40辈子,Google Play Store够你用50辈子,前提是,你必须生下来就开始玩手机。

这么多应用,不知道有没有你的贡献。估计正在看文章的你也贡献了好几个了吧。AppStore里面也有我的贡献。😊

开发一个APP不是那么容易的一件事,有很多坑等着你去踩。今天我们就抛出一个格式化时间的坑。

NSDateFormatter格式化时间

之前的文章,讲到过:NSDate和NSString相互转换。里面提到过如何讲NSDate转化成NSString。代码如下:

//获取系统当前时间
NSDate *currentDate = [NSDate date];
//用于格式化NSDate对象
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
//设置格式:zzz表示时区
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss zzz"];
//NSDate转NSString
NSString *currentDateString = [dateFormatter stringFromDate:currentDate];
//输出currentDateString
NSLog(@"%@",currentDateString);

运行起来,看看打印的内容:

2015-07-07 22:08:57.422 TestDemo[6756:1555205] 2015-07-07 22:08:57

这样写是不是没有什么问题。看着应该是没什么问题,其实问题很大。但是如果你改一下系统设置:语言设置成印度尼西亚文,时间设置成12小时制。

大家应该知道如何去设置吧,不会设置的请不要告诉我你是一名iOS开发工程师。再次编译起来,看看打印内容如下:

2015-07-07 22:09:14.928 TestDemo[6762:1555466] 2015-07-07 10.09.14 PM

是不是愣住了,怎么会这么奇葩,时间怎么是.呢?还有更奇葩的呢,你去设置设置其他语言试试,也许有更多的收获。

如何正确的格式化时间

这也是我们这两天遇到的问题,跟用户几经沟通之后,终于抓到log,发现问题竟然是格式化导致的。怎么解决呢?

这个时候NSLocale的重要性就体现出来了。NSLocale作为大家都不常用的一个类,NSLocale类是将与国家和语言相关的信息进行简单的组合,包括货币、语言、国家等的信息。

所以很简单,我们把dateFormatter的locale属性改一下即可解决这个问题。将下面代码放在dateFormatter初始化之后:

NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
dateFormatter.locale = usLocale;

看看问题解决没有,编译一下:

2015-07-07 22:20:08.411 TestDemo[6769:1556968] 2015-07-07 22:20:08

果然,问题得到完美解决了。

NSLocale用法简介

获取国家、货币、语言地区编码

既然谈到NSLocale,我们就来简单了解一下:

+ ISOCountryCodes// 所有的ISO定义的国家地区编码
+ ISOCurrencyCodes// 所有的ISO定义的货币编码
+ ISOLanguageCodes// 所有ISO定义的语言编码

以上我们可以用NSLog打印出来看一看。

监听用户本地化的设置信息

FOUNDATION_EXPORT NSString * const NSCurrentLocaleDidChangeNotification NS_AVAILABLE(10_5, 2_0);

获取当前系统设置语言的标识符

[[NSLocale currentLocale] localeIdentifier];

还有很多关于NSLocale的用法,自己动手多尝试。还有一个小问题。

NSLocale怎么读?

看了这么久的NSLocale了,你知道NSLocale怎么读吗?不要翻译噢,看看你读的到底对不对?

iOS开发自定义时间选取器

JUL 6TH, 2015 11:40 PM

又是一年的暑假日期而至,小孩子放假,都会到在外打工的父母身边。孩子想父母,父母也思念着自己的孩子。我身边的亲戚朋友的孩子 也都来了。这个暑假又该热闹起来。

努力什么时候都不晚

我有一个表妹,今年参加完高考,对自己的成绩不是特别满意。上次我回老家,刚好她给我一起来上海。准备来上海锻炼一下。

车上我问她,准备去哪上学?她说不想上了,想打工。我没有怎么劝她,我想让她体验一下打工的生活,她就知道还是上学好。

一个高中生,出来找工作,困难可想而知。经姐姐介绍,进了一家餐厅工作。工资也不是很高。干了两天,我问她怎么样?她说,高二要是来让我体验一下,我一定能考上一本。

也许真的如她所说的那样,但是谁知道呢?时间也不会倒流,她也不再可能再参加一次高考了。人只有吃过苦头,才知道努力。这是件好事,大学好好把握也是一样的。

无论处于什么困境,只要知道努力,我觉得什么时候都不晚。关注iOS开发微信公众号:iOSDevTip

自定义时间选取器

每天都随便扯扯,回到正题。今天我们做一个时间选取器,很简单,效果如下:

time

我们自定义一个LGDatePickerView,在LGDatePickerView里面实现。

背景半透明

背景是半透明的,点击的灰色背景的时候,时间选取器消失。在LGDatePickerView初始化方法里,代码如下:

- (id)init
{
    self = [super init];
    if (self) {
  //背景半透明,绑定取消方法
    UIControl *control = [[UIControl alloc] initWithFrame:SCREEN_BOUNDS];
    control.backgroundColor = [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue:0.0/255.0 alpha:0.5f];
    [self addSubview:control];
    [control addTarget:self action:@selector(actionCancel:) forControlEvents:UIControlEventTouchUpInside];     
     }
    return self;
}

绑定的actionCancel方法:

- (void)actionCancel:(id)sender
{
    [self removeFromSuperview];
}

确定取消按钮

看到上面的确定取消按钮,你会怎么做,写一个UIView上面放两个UIButton。这样做也是可以实现的。我们还可以用UIToolbar。在LGDatePickerView初始化方法里加上下面这段代码:

 // Toolbar
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, SCREEN.height - 250, SCREEN.width, 50)];
toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
UIBarButtonItem *itemCancelDone = [[UIBarButtonItem alloc] initWithTitle:@"确定" style:UIBarButtonItemStylePlain target:self action:@selector(actionConfirm:)];
UIBarButtonItem *itemCancel = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(actionCancel:)];
UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[toolbar setItems:[NSArray arrayWithObjects:itemCancel,space,itemCancelDone, nil]];
[control addSubview:toolbar];

actionCancel上面已经实现了。下面实现actionConfirm方法。它有什么作用呢?

  • 点击的时候获取到时间,然后通过代理代理出去
  • 时间选取器消失

      - (void)actionConfirm:(id)sender
      {
          if ([self.delegate respondsToSelector:@selector(datePickerView:didSelectTime:)]) {
              [self.delegate datePickerView:self didSelectTime:self.datePicker.date];
          }
          [self removeFromSuperview];
      }
    
    

代理方法

在LGDatePickerView.h

@protocol LGDatePickerViewDelegate <NSObject>

- (void)datePickerView:(LGDatePickerView *)datepicker didSelectTime:(NSDate *)time;

@end

创建UIDatePicker

在LGDatePickerView.h定义一个全局变量:

@property (nonatomic, strong) UIDatePicker *datePicker;

在LGDatePickerView初始化方法里加上下面这段代码:

UIDatePicker *datePicker = [[UIDatePicker alloc] init];
datePicker.backgroundColor = [UIColor whiteColor];
datePicker.datePickerMode = UIDatePickerModeCountDownTimer;
datePicker.date = [NSDate date];
datePicker.frame = CGRectMake(0, SCREEN.height - 200, SCREEN.width, 220);
[control addSubview:datePicker];
self.datePicker = datePicker;

使用LGDatePickerView

使用起来很简单,创建一下,然后加载self.view上面即可:

    LGDatePickerView *datePicker = [[LGDatePickerView alloc] init];
    datePicker.delegate = self;
    datePicker.datePicker.date = [NSDate date];
    datePicker.frame = self.view.bounds;
    [self.view addSubview:datePicker];

以上就实现了iOS开发自定义时间选取器,代码不难,有什么问题,欢迎提问哈。

程序员屌丝逆袭之路不是炒股

JUL 5TH, 2015 11:35 PM

最近这一段时间,你身边是不是大多数人都在谈论股票?那就对了,无论走到哪都能听到,今天又绿了,我的股票跌停了,冲上5000点啦,等等之类的话。

我还不是一个股民,一直都不是。因为不懂,不敢入市;因为有人跳楼,害怕入市;最主要的原因是,因为手里没有人民币。

人们常说:股市有风险,入市需谨慎。但是还是很多人挤破头皮,往里进。站着进去,趴着出来;笑着进去,哭着出来。

作为一名屌丝,谁不想逆袭呢,谁不想通过炒股赚钱呢?

前同事炒股翻倍

最近群里,有个前同事做后台的。他进了一家证劵公司,做后台。应该是年初进去上班的,刚好赶上一波牛市。他买了几只股,好像都不错。

其中有一只股,买的时候是30左右。在60几出的。赚了几万块钱吧。想想真的很不错,啥都不干白赚几万块钱,谁看了不心动呢。说实话,我也心动。

估计是受到他的影响,公司里有些同事也开始炒股了。当然,有的人可能早就在炒股,只是之前股市不景气,大家都不谈论罢了。

看着别人赚钱容易,到自己了估计就难了。真的是这样,尤其是股市里面的钱,真的不是那么好赚的。通过炒股走上逆袭之路,那更是难上加难。

我的模拟炒股之路

大家都在谈论股票,我也不能闲着啊。就Appstore里面找了一个模拟炒股软件,试着玩玩看。说不定能赚。

里面有100万,是用来模拟炒股的。反正,是假的,就随便挑了几只股票入手。一共投了30多万吧。还别说,当天就赚了一万多。突然发现自己有成为股神的潜质,哈哈。

紧接着,第二天,第三天,每天都能赚个两三万,第五天的时候,模拟资金已高达110多万。这要是真钱,该多好啊。那我岂不是白白赚了10万块钱。所以你想想,那些有钱的人,真的是越来越有钱。随便弄一下,几百万就来了。

与此同时,其他炒股的同事都在赚,投一万多,赚一千多。看起来还真不错。看到大家都赚钱了,我这个股票小白,模拟都能赚10万块。是不是很想入市啊。

事情并没有想象的那么简单。随后的两三周,股票大跌,各种跌停。有的股票都快跌一半了。包括我前同事买的那个股票从60多又跌回到30多了。不过幸好,他已经抛了。

并不是每个人都那么幸运。有的人都快损失过半了。这种过山车的股市,真让人受不了。炒股不仅有风险,还严重影响生活。与其这样,还不如好好思考如何提高自己的技术。

再看看我的模拟炒股战绩:

gu

股市大跌之后

经过前面的大跌,股市下一步走向如何呢?或许会继续跌一些,但是我更愿意相信股市会涨,我也希望能涨,让更多被套牢的朋友赚点。我不是股神,无法给出精准的答案。

也许在中国根本就不存在巴菲特口中的价值投资理论。有的只是政策市。

股市大跌之后,我也不再想通过股市走向逆袭之路。作为一名屌丝程序员,还是安心的做个美男子,去实现更多有价值的理想吧。

UIButton中的三个UIEdgeInsets属性(二)

JUL 4TH, 2015 2:14 PM

昨天去公司加班的人请举手,不是只有我一个吧?(😭)我觉得加班的人应该不少吧。今天周日,应该不需要去加班了。心里暗暗自喜,终于可以休息一天啦。(😄)

说到加班,应该是程序猿心里的痛啊。不加班吧,东西做不完;加班吧,身体吃不消。作为程序猿真的不容易,每天从早忙到晚。突然有一天,六点下班,看见太阳还在等我,心里被踢有多高兴。

弱弱的问一下:加班好不好?

要看这个问题问谁了。如果问老板,老板肯定美滋滋的说,加班好啊,说明你有责任心,有上进心,把公司当成自己的…

如果问我,哈哈,我当然说加班不好啦,不然会被打死的。开个玩笑。说句实话,加班肯定是不好的,尤其是对程序猿来说。每天面对电脑,每天坐着,时间长了,各种问题就凸显出来。

但是,我说加班不好有用吗?如果我要是老板,我就直接让员工在家办公。(😊)所以大家感觉支持我吧,说不定哪天我真的…

接着昨天的UIButton中的三个UIEdgeInsets属性,今天我们具体谈谈UIButton的contentEdgeInsets、titleEdgeInsets、imageEdgeInsets属性。

创建UIButton

UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(50, 200, 200, 50);
[button setTitle:@"我是UIButton" forState:UIControlStateNormal];
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor orangeColor]];
button.titleLabel.textAlignment = NSTextAlignmentLeft;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[self.view addSubview:button];

创建一个button,让button的title居左,以便观察:

1

UIButton的contentEdgeInsets属性

@property(nonatomic)          UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR; // default is UIEdgeInsetsZero

contentEdgeInsets里有一个content应该指的就是UIButton的title。

参数含义

上一篇文章我们讲了UIEdgeInsets是个结构体类型。里面有四个参数,分别是:top, left, bottom, right。这四个参数表示距离上边界、左边界、下边界、右边界的距离。

这四个参数的值可以为正值,也可以为负值。拿left举例:

left = 10; //代表以当前位置为基准,向右移动10个像素
left = -10; //代表以当前位置为基准,向左移动10个像素

向右移动20个像素

button.contentEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0);

向右移动20个像素,left = 20,就可以了。

2

向左移动20个像素

button.contentEdgeInsets = UIEdgeInsetsMake(0, -20, 0, 0);

2

UIButton的titleEdgeInsets属性

titleEdgeInsets和contentEdgeInsets的作用差不多。我们及设置contentEdgeInsets,又设置titleEdgeInsets,会怎样呢?

button.titleEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0);
button.contentEdgeInsets = UIEdgeInsetsMake(0, 20 , 0, 0);

看一下效果:

3

UIButton的titleEdgeInsets属性

创建一个带照片的button

UIButton *button = [[UIButton alloc] init];
button.frame = CGRectMake(50, 200, 200, 200);
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor orangeColor]];
[button setImage:[UIImage imageNamed:@"test"] forState:UIControlStateNormal];
[self.view addSubview:button];

运行一下:

5

向右移动50个像素

button.imageEdgeInsets = UIEdgeInsetsMake(0, 50, 0, 0);

看看效果:

6

向左移动50个像素

button.imageEdgeInsets = UIEdgeInsetsMake(0, -50, 0, 0);

看看效果:

7

大家可以自行设置其他三个参数看看效果是怎样的,自己动手便于理解。

ios

UIButton中的三个UIEdgeInsets属性(一)

JUL 3RD, 2015 11:29 PM

随着时间的推移,随着我的坚持,公众号的订阅用户已经越来越多了。非常感谢大家的信任,我会再接再厉,努力为大家提供更多优秀的文章。

当初创建iOS开发( iOSDevTip ),只是自己的兴趣。刚开始还不怎么会用微信公众号的后台,连发图文消息都不会。不知道怎么去编辑,当初的微信公众号后台也没有现在这么强大。我还以为就是个一对多的聊天工具呢。(😊)

慢慢的我学会了编辑文章,成为一个真正意义上的小编。每天负责为大家推送一些iOS相关的技术文章。每天到各大论坛、网站、大神的博客找一些好的文章。这个过程是漫长的,但是是值得的。

找文章的过程中,对自己来说,也是学习的好机会。如果没有这个公众号,我可能就看不到那么多的技术文章,也不能为大家推荐文章,自己也不会建立博客。

现在微信团队已经邀请我开通原创功能,以后,我就会多发一些原创内容。一个人的力量比较是有限的,订阅的用户如果有喜欢写技术文章的,欢迎头投稿给我,我的邮箱:worldligang@163.com

相信我,你的付出也会有回报的。

今天是周六,不知道正在看文章的你有没有在加班。没有加班的,就好好休息一下吧;加班的,我只能同情一下啦。今天我们来看看UIButton中的三个UIEdgeInsets属性。

UIEdgeInsets是什么

UIEdgeInsets是什么?我们点进去看一下:

typedef struct UIEdgeInsets {
    CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
} UIEdgeInsets;

UIEdgeInsets是个结构体类型。里面有四个参数,分别是:top, left, bottom, right。这四个参数表示距离上边界、左边界、下边界、右边界的距离。

哪三个UIEdgeInsets属性

不知道大家发现没有,UIButton里面有三个UIEdgeInsets属性,分别是:

@property(nonatomic)          UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR; // default is UIEdgeInsetsZero

@property(nonatomic)          UIEdgeInsets titleEdgeInsets;                // default is UIEdgeInsetsZero

@property(nonatomic)          UIEdgeInsets imageEdgeInsets;                // default is UIEdgeInsetsZero

contentEdgeInsets后面有个UI_APPEARANCE_SELECTOR是什么意思呢?

提示:UI_APPEARANCE_SELECTOR标记的属性都支持通过外观代理来定制。

举例,设置UIButton的contentEdgeInsets属性,可以直接调用:

[[UIButton appearance] setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, 0, 0)];

关于UIButton三个UIEdgeInsets属性的作用,下一篇文章介绍。

ios

UIButton文字居左显示

JUL 2ND, 2015 10:18 PM

题外话:时间依旧过的很快,不知不觉2015年就过去一半了。感觉自己好像没有大的改变,只能感叹时间飞逝,却不能有所收获。

我从来都不是一个安于现状的人,改变自己的想法从未停止过。我想大多数人都跟我有类似的想法。但是为什么很难有所成就呢?我觉得最重要的原因就是,只是想一下,而没有去行动

这是一个全民创业的时代,不把握机会,只能错过。错过的机会,越多遗憾就越多。有句话说:老了之后,回想人生,不会因为自己做过什么而后悔,而会因为自己没有做过什么而遗憾。不想给人生留下遗憾,所以努力去尝试是唯一的选择。

随便感慨一下。每天上班太舒服了,淡忘了自己的理想,借此提醒一下自己。

来来,收回思路,今天我们来讲如何让UIButton文字居左显示?我们都应该写过让UILabel的text居左显示。代码也非常简单。

UILabel文字居左显示

实现文字居左显示代码如下:

UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(50, 100, 200, 50);
label.text = @"我是label";
label.textAlignment = NSTextAlignmentLeft;
label.backgroundColor = [UIColor orangeColor];
[self.view addSubview:label];

运行起来看一下效果:

1

label.backgroundColor = [UIColor orangeColor];设置label的背景颜色方便我们参考。你是不是这样做的。依次类推UIButton也很简单,你肯定能想到。我们来看看。

UIButton文字居左显示

创建UIButton

UIButton *button = [[UIButton alloc] init];
//设置坐标
button.frame = CGRectMake(100, 100, 100, 50);
//设置标题
[button setTitle:@"我是UIButton" forState:UIControlStateNormal];
//设置标题颜色
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
//设置背景颜色    
[button setBackgroundColor:[UIColor orangeColor]];
[self.view addSubview:button];

以上代码是创建一个button,设置坐标、标题、和标题颜色。

让文字居左

按照UILabel文字居左的写法,UIButton应该这么写:

 button.titleLabel.textAlignment = NSTextAlignmentLeft;

运行一下看一下效果:

2

我们发现UIButton的文字还是居中显示。竟然没有居左显示,怎么办呢?进UIButton看看,还有哪些属性。很快发现:

@property(nonatomic) UIControlContentHorizontalAlignment contentHorizontalAlignment; // how to position content hozontally inside control. default is center

typedef NS_ENUM(NSInteger, UIControlContentHorizontalAlignment) {
    UIControlContentHorizontalAlignmentCenter = 0,
    UIControlContentHorizontalAlignmentLeft   = 1,
    UIControlContentHorizontalAlignmentRight  = 2,
    UIControlContentHorizontalAlignmentFill   = 3,
};

设置contentHorizontalAlignment

button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;

再次运行起来看效果:

3

果然可以,是不是看着居左显示很难看,太靠边了。很简单,设置UIButton的titleEdgeInsets属性:

button.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);

这样button的title就距左边10个像素的距离。

居右显示就很简单了:

button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;

ok,UIButton文字居左显示完成了。更多iOS技术请点击刚刚在线 : www.superqq.com

EGOCache如何检测缓存时间过期

JUL 2ND, 2015 12:38 AM

子曰:学而不思则罔,思而不学则殆。

在上一篇文章中:EGOCache缓存框架详细讲解 提到EGOCache可以设定缓存过期时间,默认是1天。查看了一下EGOCache源码,设置默认时间:

    [self setDefaultTimeoutInterval:86400];

    //86400 = 24 * 60 * 60 刚好是一天时间。

EGOCache为什么要提供设定缓存过期时间呢?或者说设定缓存过期时间有什么好处呢?我觉得最大的好处就是可以定时清除缓存。可以设置某一项的缓存时间,很方便管理缓存。

那么问题来了:

  1. EGOCache是怎么检测缓存过期时间的呢?
  2. 检测到时间过期之后,什么时候触发删除缓存项的?

带着这两个问题,我们来继续分析。

你会怎么实现

记得在公司里,老板经常会举这样的例子:

某某同志,刚来我们公司的时候,遇到问题就知道抱怨。从来不知道去思考怎么解决,只知道把问题抛给领导。工作半年下来,成长了很多。现在碰到问题,不仅把问题抛出来,而且还提供了自己的解决方案...

类似的例子,相信大家都听过。同样,既然前面我们提出这两个问题,我们也先来思考一下,如果我们来做该怎么解决?

如果让我来写的话,我脑海里初步实现方法有几个:

  1. 通过定时器来轮询,每隔一段时间检测一次。
  2. 写一个while循环来检测。
  3. 每次去读取缓存项的时候,判断缓存时间有没有过期。没过期,就返回读取的缓存项;否则,返回nil。

当然,还有一些方法,不一一例举了。仔细想想,这些方法弊端很容易显露出来。

  1. 为了小小的缓存时间,就用定时器轮询,显然是资源浪费
  2. 跟方法1差不多。
  3. 每次读取的时候判断是否过期,如果一直不读取,app的缓存会越来越大,也不可取。

这些方法都被排除了,还有好的方法吗?继续往下看:

EGOCache是怎么实现的?

仔细查看EGOCache源码,发现在initWithCacheDirectory:方法里,每次初始化EGOCache实例对象的时,会遍历一遍plist文件中所有已存在的缓存项,拿每个缓存项的时间和当前时间作比较,缓存项过期时间早于当前时间,则删除对应缓存文件,并删除 plist 文件中对应 key 的记录。

具体实现代码如下:

读取缓存项信息

_cacheInfo = [[NSDictionary dictionaryWithContentsOfFile:cachePathForKey(_directory, @"EGOCache.plist")] mutableCopy];

if(!_cacheInfo) {
    _cacheInfo = [[NSMutableDictionary alloc] init];
}

获取当前时间的NSTimeInterval

NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];

声明removedKeys保存过期的缓存项对应的key

NSMutableArray* removedKeys = [[NSMutableArray alloc] init];

遍历缓存项信息并判断缓存时间

for(NSString* key in _cacheInfo) {
    //判断缓存项过期时间是否早于当前时间
    if([_cacheInfo[key] timeIntervalSinceReferenceDate] <= now) {
        //如果缓存项过期时间早于当前时间,移除缓存项
        [[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(_directory, key) error:NULL];
        //把过期的缓存项对于的key保存到removedKeys里面
        [removedKeys addObject:key];
    }
}

删除过期缓存项对于的key

[_cacheInfo removeObjectsForKeys:removedKeys];

看到这些,是不是觉得人家思路特牛叉,反正,我是觉得这个作者不简单。到这一步就解决了吗?

EGOCache还做了什么?

细心的童鞋会发现:EGOCache是个单列类,也就是说整个程序应用周期只初始化一次。

+ (instancetype)globalCache {
    static id instance;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[[self class] alloc] init];
    });

    return instance;
}

每次初始化的时候去判断了缓存项是否过期,这样做非常正确。思考一个场景:

  1. 用户打开app,EGOCache被初始化,并判断了缓存项是否过期。
  2. 如果刚好有一些缓存项在EGOCache被初始化之后过期。这个时候我们依然可以读到这个缓存项。这就不对了。

继续分析EGOCache源码发现,EGOCache在读取一个缓存项的时候,先判断缓存项是否存在,然后读取缓存项(注意:是读取EGOCache初始化的时候没有过期的缓存项,并没有说现在没有过期),最后去判断读取到的缓存项跟当前时间相比是否过期.

具体实现如下:

- (BOOL)hasCacheForKey:(NSString*)key {
    //读取EGOCache初始化的时候没有过期的缓存项
    NSDate* date = [self dateForKey:key];
    if(date == nil) return NO;
    //判断读取到的缓存项当前是否过期
    if([date timeIntervalSinceReferenceDate] < CFAbsoluteTimeGetCurrent()) return NO;

    return [[NSFileManager defaultManager] fileExistsAtPath:cachePathForKey(_directory, key)];
}

- (NSDate*)dateForKey:(NSString*)key {
    __block NSDate* date = nil;

    dispatch_sync(_frozenCacheInfoQueue, ^{
        date = (self.frozenCacheInfo)[key];
    });

    return date;
}

EGOCache检测缓存时间过期的思路值得学习,以后遇到类似场景,完全可以借鉴。

EGOCache缓存框架详细讲解

JUL 1ST, 2015 12:10 AM

EGOCache是一个轻量级的缓存框架。用法简单方便,在现在的项目中,我就用到EGOCache来缓存下载过的照片和字符串。

有人可能会问到,缓存照片还需要用EGOCache吗?AFNetworkingSDWebImage不是已经有这些功能了吗?

是的,不过AFNetworking和SDWebImage是http。我的项目用的是socket,所以我选择EGOCache来做缓存。用下来觉得EGOCache还是挺强大的。

EGOCache简介

EGOCache is a simple, thread-safe key value cache store. It has native support for NSString, UI/NSImage, and NSData, but can store anything that implements <NSCoding>. All cached items expire after the timeout, which by default, is one day.

翻译过来就是:EGOCache一个简单、线程安全的基于 key-value 的缓存框架,原生支持NSString、UI/NSImage、和NSData,也支持储存任何实现协议的类,可以设定缓存过期时间,默认是1天。

EGOCache只有一个类,EGOCache.h和EGOCache.m两个文件。用法也比较容易掌握,仔细研究一下EGOCache.h的方法,很快就可以上手。

EGOCache只提供了磁盘缓存,没有提供内存缓存。同时,也提供了清理缓存的方法:

- (void)clearCache;

EGOCache还提供了判断缓存是否存在的方法:

- (BOOL)hasCacheForKey:(NSString* __nonnull)key;

通过Cocoapods直接加入项目

直接在你的项目的Podfile加入下面一行:

pod 'EGOCache'

然后执行:

$ pod update

EGOCache用法

用EGOCache缓存NSString

存储:

NSString *saveString = @"把我保存起来吧";
[[EGOCache globalCache] setString:saveString forKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[saveString hash]] withTimeoutInterval:24*60*60];

读取:

NSString *getSaveString = [[EGOCache globalCache] stringForKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveString" hash]]];

是不是感觉跟NSDictionary很相似,确实,前面我们说了EGOCache是基于key-value 的缓存框架。

用EGOCache缓存UIImage

存储:

 UIImage *saveImage = [UIImage imageNamed:@"iOSDevTip"];
[[EGOCache globalCache] setImage:saveImage forKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveImage" hash]] withTimeoutInterval:24*60*60];

读取:

UIImage *getSaveImage = [[EGOCache globalCache] imageForKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveImage" hash]]];

用EGOCache缓存NSData

存储:

NSData *saveData = [NSData data];
[[EGOCache globalCache] setData:saveData forKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveData" hash]] withTimeoutInterval:24*60*60];

读取:

UIImage *getSaveData = [[EGOCache globalCache] dataForKey:[NSString stringWithFormat:@"EGOImageLoader-%lu", (unsigned long)[@"SaveData" hash]]];

EGOCache源码下载

 
posted @ 2015-07-18 06:57  提灯走夜路  阅读(488)  评论(0编辑  收藏  举报