如何简化你的产品

产品从诞生之初,就是功能点的堆砌,并且随着产品生命周期的延续,功能的堆砌就会更加的明显。

过去的功能,不会再有人提及,只求功能能够正常运行就谢天谢地了。

iOS中UIButton实现双击操作

我们在日常的开发过程中,一个UIButton可能需要承载许多的操作,用得最多的当然是单击的操作,但是有的时候,我们需要使用双击操作,而apple并没有提供封装的方法,所以,我们就自己来构建一个双击的操作示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
UIButton * tabButton = [UIButton buttonWithType:UIButtonTypeCustom];

// 点击操作
[tabButton addTarget:self action:@selector(tabButtonTapped:forEvent:) forControlEvents:UIControlEventTouchDown];
// 双击操作
[tabButton addTarget:self action:@selector(repeatBtnTapped:forEvent:) forControlEvents:UIControlEventTouchDownRepeat];

- (void)tabButtonTapped:(UIButton *)sender forEvent:(UIEvent *)event {
[self performSelector:@selector(tabButtonTap:) withObject:sender afterDelay:0.2];
}

- (void)tabButtonTap:(UIButton *)sender {
NSLog(@"单击操作");
}

- (void)repeatBtnTapped:(UIButton *)sender forEvent:(UIEvent *)event {

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(tabButtonTap:) object:sender];

NSLog(@"双击操作");
}

swift高级特性一瞥

1
2
3
4
5
6
7
8
9
10
11
12
// Playground - noun: a place where people can play

import UIKit

// 1
func swap<T>(inout a: T, inout with b: T) {
(a, b) = (b, a)
}

var a = "Marin", b = "Todorov"
swap(&a, &b)
[a, b]
1
2
3
4
5
6
7
8
// 2
func flexStrings(s1: String = "", s2: String = "") -> String {
return s1 + s2 == "" ? "none" : s1 + s2
}

flexStrings()
flexStrings(s1: "hello")
flexStrings(s1: "hello", s2: "world")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 3
func sumAny(anys: Any...) -> String {
return String((anys.map({item in
switch item {
case "" as String, 0 as Int:
return -10
case let s as String where s.toInt() > 0:
return s.toInt()!
case is Int:
return item as Int
default:
return 0
}
}) as [Int]).reduce(0) {
$0 + $1
})
}

sumAny()
sumAny(Double(), 10, "-10", 2)
sumAny("Marin Todorow", 2, 22, "-3", "10", "", 0, 33, -5)

GCD中的一些高级特性

在开发中执行比较耗时的程序的时候,我们通常都是运用多线程的方式来处理的,在iOS的开发中我们可以使用GCD来处理,一旦用到了多线程就不可避免的会出现线程之间的锁的问题(死锁,读写锁,互斥锁等等)。下面我们就来谈谈在GCD中如何避免多线程操作的读写锁以前其他的一些特性。

1.运用GCD避免读写锁导致线程安全问题

假设,我们有一个DataManager类,它用来管理整个程序中的数据,再操作的时候就会出现添加数据和读取数据的操作,如果在同一个时间点,两个线程同时要对数据进行添加操作的话,则就会发生操作错误的问题,为了解决这个我们运用到GCD中的barrier和sync操作:

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
@interface DataManager ()

@property (strong, nonatomic) NSMutableArray *dataArray;
@property (strong, nonatomic) dispatch_queue_t concurrentDataQueue;

@end

@implementation DataManager

+ (instancetype)shareInstance {
static DataManager *dataManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dataManager = [[DataManager alloc] init];
dataManager.concurrentDataQueue = dispatch_queue_create("com.kingiol.gcd.dataManagerQueue", DISPATCH_QUEUE_CONCURRENT);
});
return dataManager;
}

- (NSArray *)data {
__block NSArray *returnData = nil;
dispatch_sync(self.concurrentDataQueue, ^{
returnData = [_dataArray copy];
});
return returnData;
}

- (void)addData:(id)data {
if (data) {
dispatch_barrier_async(self.concurrentDataQueue, ^{
[_dataArray addObject:data];
});
}
}

@end

通过上述的代码就能够很好的处理多线程对dataArray数组的操作,并且不会出现读写锁的问题。

2.运用GCD的group来监听一组并发是否运行结束

如果当前有3张图片,我们需要从网络上面下载,然后全部下载完成之后,我们需要统一的提醒用户下载完成,这个时候因为每一个图片下载都是并发的,传统的方法是每一个线程各自都有一个bool变量,然后我们去魂环判断这么变量是不是都被置成已完成的状态。现在我们来运用GCD中的group特性来统一处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSInteger i = 0; i < 3; i++) {
dispatch_group_enter(downloadGroup);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//下载图片程序
//在图片下载完成的block中调用:
dispatch_group_leave(downloadGroup);
});
}
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:@"全部下载完成" delegate:nil cancelButtonTitle:@"cancel" otherButtonTitles:nil, nil];
[alertView show];
});

处理UITabbar中选中图片变小的问题

最近编写的UITabbarController中发现一个奇怪的问题,就选中一个tab之后,然后你继续点击这个tab,就会发现选中的图标逐渐的变小变小,最后能够消失。

修改之前的有关tabBarItem的设置:

1
2
3
UIViewController *controller = [[UIViewController alloc] init];
[controller.tabBarItem setImageInsets:UIEdgeInsetsMake(1, 1, 1, 1)];
[controller.tabBarItem setTitle:@"首页"];

修改之后的有关tabBarItem的设置:

1
2
3
UIViewController *controller = [[UIViewController alloc] init];
[controller.tabBarItem setImageInsets:UIEdgeInsetsMake(-1, 0, 1, 0)];
[controller.tabBarItem setTitle:@"首页"];

修改了tabBarItem的图片显示模式imageInsets就可以避免问题了。

改变UITabBar的背景色

默认的UITabBar的背景色是黑色的,我们有的时候需要设置一些自定的颜色,来达到自定义的要求,下面就来说说在iOS6和iOS7中如果进行设置的,下面设置背景色为白色:

iOS6

1
2
3
4
5
6
7
8
9
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor whiteColor] CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

self.tabBar.backgroundImage = image;

iOS7

1
2
3
4
UIView *bgView = [[UIView alloc] initWithFrame:self.tabBar.bounds];
bgView.backgroundColor = [UIColor whiteColor];
[self.tabBar insertSubview:bgView atIndex:0];
self.tabBar.opaque = YES;

注册个人版苹果开发者须知

最近,注册个人开发者账号,前面的注册流程网上一大推,我在这里就不再重复了。

首先说说注册前,需要注意的地方:

  1. 需要访问appleid.apple.com对自己的账号中的地址信息进行修改,修改成你自己身份证上面的地址.
  2. 如果你的appleid已经加入到别的team里面的话,那么很抱歉,你需要使用一个新的appleid进行注册开发者计划。(或者可以从原来的team中移除,然后可以继续注册)

下面来说说我的情况:

我的appleid已经加入到公司的team中了,然后我再用这个账号注册了开发者计划,在激活的时候,激活页面始终无法正常的打开,电话咨询客服人员,然后客服发来一个链接:developer.apple.com/membercenter/uploadDocs.action,要求我上传身份证的信息。然后我打开这个页面,登陆进去,还是无法打开页面,显示:

This page cannot be viewed.

we’re unable to process your request due to an unknown error.

If you require assistance, please contact Apple Developer Support.

希望你们在注册的时候能够比较的顺利。

天天品尝iOS7甜点 :: Day 23 :: Multipeer Connectivity

这篇文章是天天品尝iOS7甜点系列的一部分,你可以查看完整的系列目录:天天品尝iOS7甜点


Introducation - 介绍

在iOS7中介绍了一个全新的框架 MultipeerConnectivity。这个是代表这传统苹果中第一个困难问题:考虑到移动设备都有多种不同的无线电技术建成的,当然,他们应该能够相互通信而无需通过互联网发送数据。在过去就可以创建一个特别的wifi网络,在蓝牙或对设备,但这些选项提供了一个非常友好的方法。伴随MultipeerConnectivity框架的变化——设置网络脱离用户和开发人员,通过与技术无关的API,而通信发生。

框架在现实中无论技术具备——无论是蓝牙,或wifi,要么使用基础设施网络,或特别的网络如果设备不共享相同的网络。这是真正的,用户就可以选择它周围的设备希望连接到框架将处理所有的休息。甚至能够使用一个节点作为一个路由器2节点之间相互看不到mesh-network的方式。

在今天的帖子里,我们会通过代码的运行需要建立一个multipeer这样的网络,以及如何在设备之间发送数据。

本章的实例程序能够在github上面进行访问,访问地址:github.com/ShinobiControls/iOS7-day-by-day

Browsing for devices - 查找浏览设备

为了发送数据,有必要建立一个设备之间的连接,这是完成一个设备“浏览”适当的设备范围内。可以请求发送到这些设备之一,它将提醒用户,允许他们接受或拒绝连接。如果连接被接受,那么框架将建立链接,允许数据被转移。

有2种方法可以浏览本地设备——一个视觉的,和一个可编程的版本。我们只是去看看视觉的方法。

,