2015-12-01 09:43:37 VNanyesheshou 阅读数 6766

最近公司提供了一个学习iOS的机会,问我是否愿意学习iOS,还是继续只做android开发。我感觉非常幸运,能有此机会去学习iOS,当即说要学习iOS开发。

学习了几天啦,做了一个小demo实现了获取经纬度,海拔,航向,及具体位置信息的功能。

iOS使用定位不像android直接指定使用gps,获取网络获取。iOS定位需要使用Core Location框架,它提供了三种技术来获取位置:GPS、蜂窝或WiFi。

1   GPS卫星  优点最为准确,缺点 耗电量大,不能遮挡(建筑物内不行)

2   WI-FI通过WIFI路由器定位 优点比较省电,经济实惠

3   蜂窝式移动电话基站。通过移动运营商基站定位 误差比较大

在这些技术中,GPS最为精准,如果有GPS硬件,Core Location将优先使用它。如果设备没有GPS硬件(如WiFi iPad)或使用GPS获取当前位置时失败,

Core Location将退而求其次,选择使用WiFi,再次则使用蜂窝。

首先看一下定位的类 CLLocationManager 的方法


要使用位置管理器,必须首先将框架Core Location加入到项目中,再导入其接口文件:

导入框架的过程如下图所示:


#import<CoreLocation/CoreLocation.h>

还需要实现代理CLLocationManagerDelegate
如下ViewController.h

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@interface ViewController : UIViewController <CLLocationManagerDelegate>{
    CLLocationManager *_lm;
    NSString *_latitude;
    NSString *_longitude;
}
- (IBAction)startLocation;
- (IBAction)stopLocation;
@property (weak, nonatomic) IBOutlet UILabel *latLon;
@property (weak, nonatomic) IBOutlet UILabel *city;
@property (weak, nonatomic) IBOutlet UILabel *location;
@end

初始化定位服务,定位精度和位置更新距离可以根据上面的方法自行设置。

这里需要提示的是:iOS 8 还提供了更加人性化的定位服务选项。App 的定位服务不再仅仅是关闭或打开。

现在,定位服务的启用提供了三个选项,「永不」「使用应用程序期间」和「始终」。同时,考虑到能耗问题,如果一款 App 要求始终能在后台开启定位服务,iOS 8 不仅会在首次打开 App 时主动向你询问,还会在日常使用中弹窗提醒你该 App 一直在后台使用定位服务,并询问你是否继续允许。在iOS7及以前的版本,如果在应用程序中使用定位服务只要在程序中调用 startUpdatingLocation方法应用就会询问用户是否允许此应用是否允许使用定位服务,同时在提示过程中可以通过在info.plist 中配置通过配置Privacy - Location Usage Description告诉用户使用的目的,同时这个配置是可选的。 
但是在iOS8中配置配置项发生了变化,可以通过配置NSLocationAlwaysUsageDescription或者 NSLocationWhenInUseUsageDescription来告诉用户使用定位服务的目的,并且注意这个配置是必须的,如果不进行配置则默 认情况下应用无法使用定位服务,打开应用不会给出打开定位服务的提示,除非安装后自己设置此应用的定位服务。同时,在应用程序中需要根据配置对 requestAlwaysAuthorization或locationServicesEnabled方法进行请求。


调用方法requesetAlwaysAuthorization则需要在info.plist中配置NSLocationAlwaysUsageDescription,type为string,value可填可不填。

调用方法requesetWhenInUseAuthorization则需要在info.plist中配置NSLocationWhenInUseUsageDescription,type为string,value可可不填。

这样才能获取到位置信息。

#import "ViewController.h"

#define IS_IOS8 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8)

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    if ([CLLocationManager locationServicesEnabled]) {
        if (nil == _lm) {
            _lm = [[CLLocationManager alloc]init];
            _lm.delegate = self;
            //设置定位精度
            _lm.desiredAccuracy = kCLLocationAccuracyBest;
            //设置位置更新的最小距离
            _lm.distanceFilter = 100.f;
            if (IS_IOS8) {//ios8之后点版本需要使用下面的方法才能定位。使用一个即可。
                //[_lm requestAlwaysAuthorization];
                [_lm requestWhenInUseAuthorization];
            }
        }
    }else{
        NSLog(@"定位服务不可利用");
    }
}

- (IBAction)startLocation{
    NSLog(@"开始定位");
    [_lm startUpdatingLocation];
}

- (IBAction)stopLocation {
    NSLog(@"停止定位");
    [_lm stopUpdatingLocation];
}


- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    //NSLog(@"location %@",error);
}

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
    _latitude = [NSString stringWithFormat:@"%3.5f",newLocation.coordinate.latitude];
    _longitude = [NSString stringWithFormat:@"%3.5f",newLocation.coordinate.longitude];

}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    // 设备的当前位置
    CLLocation *currLocation = [locations firstObject];
    //获取经纬度
    _latitude = [NSString stringWithFormat:@"%3.5f",currLocation.coordinate.latitude];
    _longitude = [NSString stringWithFormat:@"%3.5f",currLocation.coordinate.longitude];
    _latLon.text =[NSString stringWithFormat:@"lat %@,\nlong %@",_latitude,_longitude];
    //获取海拔 航向 速度
    NSLog(@"经度:%@,纬度:%@,海拔:%f,航向:%f,行走速度:%f",_longitude,_latitude,currLocation.altitude,currLocation.course,currLocation.speed);
    CLGeocoder *geoCd = [[CLGeocoder alloc] init];//反编码通过经纬度获取具体位置信息。
    [geoCd reverseGeocodeLocation:currLocation completionHandler:^(NSArray *array, NSError *error){
        if (array.count > 0){
            CLPlacemark *placemark = [array objectAtIndex:0];
            //将获得的所有信息显示到label上
            self.location.text = placemark.name;
            //获取城市
            NSString *cty = placemark.locality;
            if (!cty) {
                //四大直辖市的城市信息无法通过locality获得,只能通过获取省份的方法来获得(如果city为空,则可知为直辖市)
                cty = placemark.administrativeArea;
            }
            self.city.text = cty;
            NSLog(@"city = %@", cty);
        }
        else if (error == nil && [array count] == 0)
        {
            NSLog(@"No results were returned.");
        }
        else if (error != nil)
        {
            NSLog(@"An error occurred = %@", error);
        }
    }];  
}
@end

仔细看上面的代码,你会发现两个地方都在获取经纬度,你会很诧异吧,

这是因为

-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation

这个方法在ios6中已经废除变成另一个方法了。

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations

可以通过locations的下标获取新的定位和上一次的定位信息。

效果如图所示:


点击开始定位按钮,会startUpdatingLocation,由于定位服务是比较费电的,不用的时候要及时关闭定位,也可以获取定位成功后直接调用

stopUpdatingLocation停止定位,也就是在方法(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations中直接停止。



代码下载地点:http://pan.baidu.com/s/1eQuLPIE

有什么问题欢迎指正,大家一起进步啊。

2019-04-15 14:53:29 u012881779 阅读数 693

 系统提示按钮字体颜色默认是蓝色,因为是在项目优化时产生的需求故使用拓展的方式解决。

#import "UIAlertController+GSActionBtn.h"

@implementation UIAlertController (GSActionBtn)

+ (void)load {
    // 只执行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [NSObject exchangeInstanceMethodWithSelfClass:UIAlertController.class originalSelector:@selector(addAction:) swizzledSelector:@selector(GSActionBtn_AddAction:)];
    });
}

- (void)GSActionBtn_AddAction:(UIAlertAction *)action {
    if ([action.title isEqualToString:@"取消"] && self.preferredStyle == UIAlertControllerStyleAlert) {
        UIColor *tempColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1];
        [action setValue:tempColor forKey:@"_titleTextColor"];
    }
    [self GSActionBtn_AddAction:action];
}

@end

示意图

2017-12-01 15:10:14 binglan520 阅读数 120

 
  1. 进程与线程
  • 进程概念: 进程是程序在计算机上的一次执行活动,打开一个app,就开启了一个进程,可包含多个线程。
  • 线程概念: 独立执行的代码段,一个线程同时间只能执行一个任务,反之多线程并发就可以在同一时间执行多个任务。
  • iOS程序中,主线程(又叫作UI线程)主要任务是处理UI事件,显示和刷新UI,(只有主线程有直接修改UI的能力)耗时的操作放在子线程(又叫作后台线程、异步线程)。在iOS中开子线程去处理耗时的操作,可以有效提高程序的执行效率,提高资源利用率。但是开启线程会占用一定的内存,(主线程的堆栈大小是1M,第二个线程开始都是512KB,并且该值不能通过编译器开关或线程API函数来更改)降低程序的性能。所以一般不要同时开很多线程。

 
  1. 线程相关
  • 同步线程:同步线程会阻塞当前线程去执行线程内的任务,执行完之后才会反回当前线程。
  • 异步线程:异步线程不会阻塞当前线程,会开启其他线程去执行线程内的任务。
  • 串行队列:线程任务按先后顺序逐个执行(需要等待队列里面前面的任务执行完之后再执行新的任务)。
  • 并发队列:多个任务按添加顺序一起开始执行(不用等待前面的任务执行完再执行新的任务),但是添加间隔往往忽略不计,所以看着像是一起执行的。
  • 并发VS并行:并行是基于多核设备的,并行一定是并发,并发不一定是并行。
  1. 多线程中会出现的问题
  • Critical Section(临界代码段) 指的是不能同时被两个线程访问的代码段,比如一个变量,被并发进程访问后可能会改变变量值,造成数据污染(数据共享问题)。
  • Race Condition (竞态条件) 当多个线程同时访问共享的数据时,会发生争用情形,第一个线程读取改变了一个变量的值,第二个线程也读取改变了这个变量的值,两个线程同时操作了该变量,此时他们会发生竞争来看哪个线程会最后写入这个变量,最后被写入的值将会被保留下来。
  • Deadlock (死锁) 两个(多个)线程都要等待对方完成某个操作才能进行下一步,这时就会发生死锁。
  • Thread Safe(线程安全) 一段线程安全的代码(对象),可以同时被多个线程或并发的任务调度,不会产生问题,非线程安全的只能按次序被访问。
    • 所有Mutable对象都是非线程安全的,所有Immutable对象都是线程安全的,使用Mutable对象,一定要用同步锁来同步访问(@synchronized)。
    • 互斥锁:能够防止多线程抢夺造成的数据安全问题,但是需要消耗大量的资源
    • 原子属性(atomic)加锁
    • atomic: 原子属性,为setter方法加锁,将属性以atomic的形式来声明,该属性变量就能支持互斥锁了。
    • nonatomic: 非原子属性,不会为setter方法加锁,声明为该属性的变量,客户端应尽量避免多线程争夺同一资源。
  • Context Switch (上下文切换) 当一个进程中有多个线程来回切换时,context switch用来记录执行状态,这样的进程和一般的多线程进程没有太大差别,但会产生一些额外的开销。

前言

对初学者来说,GCD似乎是一道迈不过去的坎,很多人在同步、异步、串行、并行和死锁这几个名词的漩涡中渐渐放弃治疗。本文将使用图文表并茂的方式给大家形象地解释其中的原理和规律。

 

线程、任务和队列的概念

1.png

异步、同步 & 并行、串行的特点

2.png

一条重要的准则

一般来说,我们使用GCD的最大目的是在新的线程中同时执行多个任务,这意味着我们需要两项条件:

 

  • 能开启新的线程

  • 任务可以同时执行

  • 结合以上两个条件,也就等价“开启新线程的能力 + 任务同步执行的权利”,只有在满足能力与权利这两个条件的前提下,我们才可以在同时执行多个任务。

 

所有组合的特点

3.png

(一)异步执行 + 并行队列

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

//异步执行 + 并行队列

- (void)asyncConcurrent{

    //创建一个并行队列

    dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT);

 

    NSLog(@"---start---");

 

    //使用异步函数封装三个任务

    dispatch_async(queue, ^{

        NSLog(@"任务1---%@", [NSThread currentThread]);

    });

    dispatch_async(queue, ^{

        NSLog(@"任务2---%@", [NSThread currentThread]);

    });

    dispatch_async(queue, ^{

        NSLog(@"任务3---%@", [NSThread currentThread]);

    });

 

    NSLog(@"---end---");

}

打印结果:

1

2

3

4

5

---start---

  ---end---

  任务3---{number = 5, name = (null)}

  任务2---{number = 4, name = (null)}

  任务1---{number = 3, name = (null)}

解释

 

  • 异步执行意味着

    • 可以开启新的线程

    • 任务可以先绕过不执行,回头再来执行

  • 并行队列意味着

    • 任务之间不需要排队,且具有同时被执行的“权利”

  • 两者组合后的结果

    • 开了三个新线程

    • 函数在执行时,先打印了start和end,再回头执行这三个任务

    • 这三个任务是同时执行的,没有先后,所以打印结果是“任务3-->任务2-->任务1”

步骤图

4.png

(二)异步执行 + 串行队列

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

//异步执行 + 串行队列

- (void)asyncSerial{

    //创建一个串行队列

    dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);

 

    NSLog(@"---start---");

    //使用异步函数封装三个任务

    dispatch_async(queue, ^{

        NSLog(@"任务1---%@", [NSThread currentThread]);

    });

    dispatch_async(queue, ^{

        NSLog(@"任务2---%@", [NSThread currentThread]);

    });

    dispatch_async(queue, ^{

        NSLog(@"任务3---%@", [NSThread currentThread]);

    });

    NSLog(@"---end---");

}

 

打印结果:

1

2

3

4

5

 ---start---

 ---end---

任务1---{number = 3, name = (null)}

任务2---{number = 3, name = (null)}

任务3---{number = 3, name = (null)}

 

解释

  • 异步执行意味着

    • 可以开启新的线程

    • 任务可以先绕过不执行,回头再来执行

  • 串行队列意味着

    • 任务必须按添加进队列的顺序挨个执行

  • 两者组合后的结果

    • 开了一个新的子线程

    • 函数在执行时,先打印了start和end,再回头执行这三个任务

    • 这三个任务是按顺序执行的,所以打印结果是“任务1-->任务2-->任务3”

步骤图

5.png

(三)同步执行 + 并行队列

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

//同步执行 + 并行队列

- (void)syncConcurrent{

    //创建一个并行队列

    dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT);

 

    NSLog(@"---start---");

    //使用同步函数封装三个任务

    dispatch_sync(queue, ^{

        NSLog(@"任务1---%@", [NSThread currentThread]);

    });

    dispatch_sync(queue, ^{

        NSLog(@"任务2---%@", [NSThread currentThread]);

    });

    dispatch_sync(queue, ^{

        NSLog(@"任务3---%@", [NSThread currentThread]);

    });

    NSLog(@"---end---");

}

打印结果:

1

2

3

4

5

---start---

  任务1---{number = 1, name = main}

  任务2---{number = 1, name = main}

  任务3---{number = 1, name = main}

  ---end---

解释

  • 同步执行执行意味着

    • 不能开启新的线程

    • 任务创建后必须执行完才能往下走

  • 并行队列意味着

    • 任务必须按添加进队列的顺序挨个执行

  • 两者组合后的结果

    • 所有任务都只能在主线程中执行

    • 函数在执行时,必须按照代码的书写顺序一行一行地执行完才能继续

  • 注意事项

    • 在这里即便是并行队列,任务可以同时执行,但是由于只存在一个主线程,所以没法把任务分发到不同的线程去同步处理,其结果就是只能在主线程里按顺序挨个挨个执行了

步骤图

6.png

(四)同步执行+ 串行队列

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

- (void)syncSerial{

    //创建一个串行队列

    dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);

 

    NSLog(@"---start---");

    //使用异步函数封装三个任务

    dispatch_sync(queue, ^{

        NSLog(@"任务1---%@", [NSThread currentThread]);

    });

    dispatch_sync(queue, ^{

        NSLog(@"任务2---%@", [NSThread currentThread]);

    });

    dispatch_sync(queue, ^{

        NSLog(@"任务3---%@", [NSThread currentThread]);

    });

    NSLog(@"---end---");

}

 

打印结果:

1

2

3

4

5

  ---start---

  任务1---{number = 1, name = main}

  任务2---{number = 1, name = main}

  任务3---{number = 1, name = main}

  ---end---

解释

  • 这里的执行原理和步骤图跟“同步执行+并发队列”是一样的,只要是同步执行就没法开启新的线程,所以多个任务之间也一样只能按顺序来执行,

(五)异步执行+主队列

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

- (void)asyncMain{

    //获取主队列

    dispatch_queue_t queue = dispatch_get_main_queue();

 

    NSLog(@"---start---");

    //使用异步函数封装三个任务

    dispatch_async(queue, ^{

        NSLog(@"任务1---%@", [NSThread currentThread]);

    });

    dispatch_async(queue, ^{

        NSLog(@"任务2---%@", [NSThread currentThread]);

    });

    dispatch_async(queue, ^{

        NSLog(@"任务3---%@", [NSThread currentThread]);

    });

    NSLog(@"---end---");

}

 

打印结果:

1

2

3

4

5

  ---start---

  ---end---

  任务1---{number = 1, name = main}

  任务2---{number = 1, name = main}

  任务3---{number = 1, name = main}

 

解释

  • 异步执行意味着

    • 可以开启新的线程

    • 任务可以先绕过不执行,回头再来执行

  • 主队列跟串行队列的区别

    • 队列中的任务一样要按顺序执行

    • 主队列中的任务必须在主线程中执行,不允许在子线程中执行

  • 以上条件组合后得出结果:

    • 所有任务都可以先跳过,之后再来“按顺序”执行

步骤图

7.png

(六)同步执行+主队列(死锁)

实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

- (void)syncMain{

    //获取主队列

    dispatch_queue_t queue = dispatch_get_main_queue();

 

    NSLog(@"---start---");

    //使用同步函数封装三个任务

    dispatch_sync(queue, ^{

        NSLog(@"任务1---%@", [NSThread currentThread]);

    });

    dispatch_sync(queue, ^{

        NSLog(@"任务2---%@", [NSThread currentThread]);

    });

    dispatch_sync(queue, ^{

        NSLog(@"任务3---%@", [NSThread currentThread]);

    });

    NSLog(@"---end---");

}

打印结果:

1

  ---start---

解释

  • 主队列中的任务必须按顺序挨个执行

  • 任务1要等主线程有空的时候(即主队列中的所有任务执行完)才能执行

  • 主线程要执行完“打印end”的任务后才有空

  • “任务1”和“打印end”两个任务互相等待,造成死锁

步骤图

8.png

2014-08-05 11:23:14 cjj198561 阅读数 5909

编译准备

1.代码下载

在mac下面执行:wget http://downloads.sourceforge.net/project/faac/faac-src/faac-1.28/faac-1.28.tar.gz

也可以用网页打开下载,不过我用网页打开下载老是失败,后来就命令下载一次性成功。

 

2.代码编译

下载以后解压文件,解压以后的文件名修改为faac,如图:

 

 

3.写脚本文件

编写build-faac.sh文件,内容如下:

 

#!/bin/sh

CONFIGURE_FLAGS="--enable-static --with-pic"

ARCHS="arm64 armv7s armv7 x86_64 i386"

# directories
SOURCE="faac"
FAT="fat-faac"

SCRATCH="scratch-faac"
# must be an absolute path
THIN=`pwd`/"thin-faac"

COMPILE="y"
LIPO="y"

if [ "$*" ]
then
if [ "$*" = "lipo" ]
then
# skip compile
COMPILE=
else
ARCHS="$*"
if [ $# -eq 1 ]
then
# skip lipo
LIPO=
fi
fi
fi

if [ "$COMPILE" ]
then
CWD=`pwd`
for ARCH in $ARCHS
do
echo "building $ARCH..."
mkdir -p "$SCRATCH/$ARCH"
cd "$SCRATCH/$ARCH"

if [ "$ARCH" = "i386" -o "$ARCH" = "x86_64" ]
then
PLATFORM="iPhoneSimulator"
CPU=
if [ "$ARCH" = "x86_64" ]
then
SIMULATOR="-mios-simulator-version-min=7.0"
HOST=
else
SIMULATOR="-mios-simulator-version-min=5.0"
HOST="--host=i386-apple-darwin"
fi
else
PLATFORM="iPhoneOS"
if [ $ARCH = "armv7s" ]
then
CPU="--cpu=swift"
else
CPU=
fi
SIMULATOR=
HOST="--host=arm-apple-darwin"
fi

XCRUN_SDK=`echo $PLATFORM | tr '[:upper:]' '[:lower:]'`
CC="xcrun -sdk $XCRUN_SDK clang -Wno-error=unused-command-line-argument-hard-error-in-future"
AS="$CWD/$SOURCE/extras/gas-preprocessor.pl $CC"
CFLAGS="-arch $ARCH $SIMULATOR"
CXXFLAGS="$CFLAGS"
LDFLAGS="$CFLAGS"

CC=$CC CFLAGS=$CXXFLAGS LDFLAGS=$LDFLAGS CPPFLAGS=$CXXFLAGS CXX=$CC CXXFLAGS=$CXXFLAGS  $CWD/$SOURCE/configure \
$CONFIGURE_FLAGS \
$HOST \
--prefix="$THIN/$ARCH" \
--disable-shared \
--without-mp4v2

make clean && make && make install-strip
cd $CWD
done
fi

if [ "$LIPO" ]
then
echo "building fat binaries..."
mkdir -p $FAT/lib
set - $ARCHS
CWD=`pwd`
cd $THIN/$1/lib
for LIB in *.a
do
cd $CWD
lipo -create `find $THIN -name $LIB` -output $FAT/lib/$LIB
done

cd $CWD
cp -rf $THIN/$1/include $FAT
fi

 

 

 

4.编译

为编写的文件增加执行权限

chmod +x build-faac.sh

然后执行脚本

./build-faac.sh

完成以后会生成如下目录,对应的库和头文件在fat-faac文件夹里面

 

fat-faac是thin-faac里面的各个平台合并以后的库和头文件

微信打赏
微信打赏
2016-08-22 14:41:35 yuqingzhude 阅读数 2529

公司做点赞功能,双击web实际只反应一次,所以给点赞按钮添加双击手势,双击执行单击操作
做法参考了这篇博文 :http://blog.163.com/dong_chen/blog/static/25607501420162111248592/
依据需求稍有修改,实现如下:
1. 给按钮添加如下两个事件

[_praiseBtn addTarget:self action:@selector(praiseBtnTapped:) forControlEvents:UIControlEventTouchDown];
[_praiseBtn addTarget:self action:@selector(praiseBtnRepeatTapped:) forControlEvents:UIControlEventTouchDownRepeat];

2.实现不同event点击方法实现

- (void)praiseBtnTapped:(UIButton *)btn
{
    [self performSelector:@selector(praiseBtnClicked:) withObject:btn afterDelay:0.2];
}
- (void)praiseBtnRepeatTapped:(UIButton *)btn
{
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(praiseBtnClicked:) object:btn];
    [self praiseBtnClicked:btn];
}

注:这里和范例有改变,范例支持一直点击,我这里双击之后不再做延时操作,直接就取消单击延时,直接执行单击操作

原文 原理解释:
原理是这样的:我们给button设置的响应事件与常规相异,UIControlEventTouchDown是点击下去时响应,而我们一般用来UIControlEventTouchUpInside进行点击事件,在其响应方法里面进行延时操作完成单击事件,在UIControlEventTouchDownRepeat响应重复按下事件,此时会响应按下操作两次,重复按下一次,所以在UIControlEventTouchDownRepeat里用函数cancelPreviousPerformRequestsWithTarget取消延时操作,并执行双击操作;
这种做法我们并不陌生,在常用第三方ASIHTTPRequest和MBProgressHUD 里面都有用过;

其实网上还要其他的做法,比如touchBegin什么的,但是感觉这种方法要好一些

没有更多推荐了,返回首页