Gowhich

Durban's Blog

Method 1: The Cross-Browser CSS Way

The easiest way to do this is to make use of the built-in Django {% cycle %} tag. Here’s how to use it for a table containing blog entries:

1
2
3
4
5
6
7
8
9
10
11
12
13
<table>
<tbody>
{% for blog in blogs %}
{% for entry in blog.entries %}
<tr class="{% cycle 'odd' 'even' %}">
{{entry.date}}
{{entry.title}}
{{entry.comments}}
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>

Method 2: The Pure CSS Way

1
2
tbody tr:nth-child(even) td {background: #bbeebb;}
tbody tr:nth-child(odd) td {background: #e5f9e5;}

关于 django 权限控制,也是出于项目需求,一般的项目都差不多需要这样的权限控制

在django中,这里实现的其实是最简单的控制,非登录用户禁止访问产品管理界面,在django中只需要在view函数中增加@login_required修饰符即可:

1
2
3
4
5
6
7
8
9
10
@login_required
def woman(request):
if request.user.is_authenticated():
user = request.user;
else:
user = request.user;

items_woman = Woman.objects.filter(is_show=0).order_by('-create_date')[:10]

return render_to_response('accounts/woman.html',{'user':user,'action':'woman','items':items_woman},context_instance=RequestContext(request))

修饰符实现了如下功能:

如果用户没有登录,重定向到/account/login/,并且把当前绝对url作为next参数用get方法传递过去;
如果已经正常登录,则直接正常执行视图函数;

这样例子中需要的功能就实现了。但是这充其量是“登录限制”,而更常见的需求是“访问控制”,即区分已经登录的用户,对不同的视图有不同的访问权限。因为我们的例子中没有涉及到,所以只把相关的做法简单例举在下面:

访问控制通过django的request.user.has_perm()实现,函数返回true和false。表示该用户是否有权限,而权限是auth应用中定义的Permission类型;User与Permission是many-to-many的关系

django还提供了一个@permission_required修饰符,来限定view函数只有在User具有相应权限的情况下才能访问

django对于每个模型类,自动增加add,change,delete三种权限,以便于控制权限,也可以自己设定自己的权限

这部分代码可以自己实现

关于django的时间格式的问题,最近在做项目中,进坑啦,python基础没怎么学,就只有这样啦,继续努力

简单的时间格式是这样的:

1
2
datetime.datetime.now()
#2012-03-15 11:50:57.728000

这个会返回 microsecond。因此这个是我们不需要的。所以得做一下修改

1
datetime.datetime.now().strftime("%Y-%m-%d %H:%I:%S");

格式化之后,就得到了我们常见的格式了。
附:strftime参数

1
strftime(format[, tuple]) -> string

将指定的struct_time(默认为当前时间),根据指定的格式化字符串输出
python中时间日期格式化符号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59
%S 秒(00-59)

%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身

一个很关键的并且要常记住的,就是代码中所有字符串都统一使用unicode,而不是str。这样,自己就能很清楚要处理的字符串类型了。请记住,是所有,任何地方。
例如:

1
2
3
4
5
>>> s1 = u'%s欢迎您!' % u'北京'
>>> s1
u'\u5317\u4eac\u6b22\u8fce\u60a8\uff01'
>>> print s1
北京欢迎你!

若像这样,就会抛异常:

1
2
3
4
>>> s2 = '%s欢迎您!' % u'北京'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 2: ordinal not in range(128)

由UnicodeDecodeError可猜想得到,解析器尝试使用ascii对’%s欢迎您!’进行解码,由于’%s欢迎您!’实际是使用utf-8编码的(这是我系统终端默认的),所以使用ascii解码肯定会错,只要如下,就可以重现这个异常了:

1
2
3
4
>>> s2 = '%s欢迎您!'.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6 in position 2: ordinal not in range(128)

分清encodedecodestr --> decode(c) --> unicode, unicode --> encode(c) --> str,其中编码类型c必须相同。

将unicode字符串写入文件前先使用特定编码对其进行编码(如unicodestr.encode('utf-8'))得到str,保证写入文件的是str;从文件读取到str,然后对其进行解码(如encodestr.decode('utf-8'))得到unicode。这是互逆的两个操作,编码类型一定要一致,否则会出现异常。

自己支持了unicode,但是你团队的其他人是否都使用unicode呢?你使用的其他模块是否也使用unicode呢?这个一定要清楚的,不然同样会出现许多因为编码问题的异常。

最近看了一下关于手机蓝牙的相关东西,涉及到了GameKit这个东西,不知道干嘛用的,一眼望过去以为是游戏的东西,不过看过文档后,其实也可以用在游戏中的。不过这里主要是蓝牙这方面的

关于聊天,其实就是就几个过程1,连接;2,传输数据和处理数据

关于这个过程其实我们可以直接自己写一个辅助类来解决就好了

我这边摘录了以为大牛的帮助类

GameKitHelper.h

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
//
// GameKitHelper.h
// Simple GameKit
//
// Created by david on 13-8-22.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <GameKit/GameKit.h>

#define DO_DATA_CALLBACK(X, Y) if (self.dataDelegate && [self.dataDelegate respondsToSelector:@selector(X)]) [self.dataDelegate performSelector:@selector(X) withObject:Y];
#define showAlert(format, ...) myShowAlert(__LINE__, (char *)__FUNCTION__, format, ##__VA_ARGS__)
#define BARBUTTON(TITLE, SELECTOR) [[UIBarButtonItem alloc] initWithTitle:TITLE style:UIBarButtonItemStylePlain target:self action:SELECTOR]



@protocol GameKitHelperDataDelegate <NSObject>
@optional
-(void) connectionEstablished;
-(void) connectionLost;
-(void) sentData: (NSString *) errorMessage;
-(void) receivedData: (NSData *)data;
@end


@interface GameKitHelper : NSObject<GKPeerPickerControllerDelegate, GKSessionDelegate>
{
NSString *sessionID;
id<GameKitHelperDataDelegate> dataDelegate;
UIViewController *viewController;

GKSession *session;
BOOL isConnected;
}

@property (retain) id dataDelegate;
@property (retain) UIViewController *viewController;
@property (retain) NSString *sessionID;
@property (retain) GKSession *session;
@property (assign) BOOL isConnected;

+(void) connect;
+(void) disconnect;
+(void) sendData: (NSData *)data;
+(void) assignViewController: (UIViewController *) aViewController;
+(GameKitHelper *) sharedInstance;
@end

GameKitHelper.m

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//
// GameKitHelper.m
// Simple GameKit
//
// Created by david on 13-8-22.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import "GameKitHelper.h"

@implementation GameKitHelper
@synthesize dataDelegate;
@synthesize viewController;
@synthesize session;
@synthesize sessionID;
@synthesize isConnected;


//Simple Alert Utility
void myShowAlert(int line, char *functname, id formatstring, ...)
{
va_list arglist;
if(!formatstring)return;
va_start(arglist, formatstring);
id outstring = [[NSString alloc] initWithFormat:formatstring
arguments:arglist];
va_end(arglist);
UIAlertView *av = [[UIAlertView alloc] initWithTitle:outstring
message:nil
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[av show];
}

#pragma mark - Shared Instance
static GameKitHelper *sharedInstance = nil;

+(GameKitHelper *) sharedInstance
{
if(!sharedInstance)
{
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}

#pragma mark - Data Sharing
-(void) sendDataToPeers: (NSData *)data
{
NSError *error;
BOOL didSend = [self.session sendDataToAllPeers:data
withDataMode:GKSendDataReliable
error:&error];
if(!didSend)
{
NSLog(@"Error sending data to peers: %@", [error localizedDescription]);
}
DO_DATA_CALLBACK(sentData:, (didSend ? nil : [error localizedDescription]));
}

-(void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession:(GKSession *)session context:(void *)context
{
DO_DATA_CALLBACK(receivedData:, data);
}

#pragma mark - Connections
-(void) startConnection
{
if(self.isConnected)
{
GKPeerPickerController *picker = [[GKPeerPickerController alloc] init];
picker.delegate = self;
picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
[picker show];
if(self.viewController)
{
self.viewController.navigationItem.rightBarButtonItem = nil;
}
}
}

//Dismiss the peeer picker on cancel
-(void) peerPickerControllerDidCancel:(GKPeerPickerController *)picker
{
if(self.viewController)
{
self.viewController.navigationItem.rightBarButtonItem = BARBUTTON(@"Connect", @selector(startConnection));
}
}

-(void) peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session
{
[picker dismiss];
[self.session setDataReceiveHandler:self
withContext:nil];
isConnected = YES;
DO_DATA_CALLBACK(connectionEstablished, nil);
}

-(GKSession *) peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type
{
if(!self.session)
{
self.session = [[GKSession alloc] initWithSessionID:(self.sessionID ? self.sessionID : @"Sample Session")
displayName:nil
sessionMode:GKSessionModePeer];
self.session.delegate = self;
}

return self.session;

}

#pragma mark - Session Handling
-(void) disconnect
{
[self.session disconnectFromAllPeers];
self.session = nil;
}

-(void) session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state
{
/* STATES: GKPeerStateAvailable, = 0, GKPeerStateUnavailable, = 1, GKPeerStateConnected, = 2,
GKPeerStateDisconnected, = 3, GKPeerStateConnecting = 4 */
NSArray *states = [NSArray arrayWithObjects:@"Available", @"Unavailable", @"Connected", @"Disconnected", @"Connecting", nil];
NSLog(@"Peer state is now %@",[states objectAtIndex:state]);

if(state == GKPeerStateConnected)
{
if(self.viewController)
{
self.viewController.navigationItem.rightBarButtonItem = BARBUTTON(@"Disconnect", @selector(disconnect));
}


if(state == GKPeerStateDisconnected)
{
self.isConnected = NO;
showAlert(@"Lost connection with peer. You are no longer connected to another device.");
[self disconnect];
if(self.viewController)
{
self.viewController.navigationItem.rightBarButtonItem = BARBUTTON(@"Connect", @selector(startConnection));
DO_DATA_CALLBACK(connectionLost, nil);
}
}
}

}

-(void) assignViewController: (UIViewController *)aViewController
{
self.viewController = aViewController;
self.viewController.navigationItem.rightBarButtonItem = BARBUTTON(@"Connect", @selector(startConnection));
}

#pragma mark - Class utility methods
+(void) connect
{
[[self sharedInstance] startConnection];
}

+(void) disconnect
{
[[self sharedInstance] disconnect];
}

+(void) sendData: (NSData *)data
{
[[self sharedInstance] sendDataToPeers:data];
}

+(void) assignViewController: (UIViewController *) aViewController
{
[[self sharedInstance] assignViewController:aViewController];
}



@end

然后使用这里类,做了一个简单的示例,我因为就一个iphone,真实的两个手机之间的连接与信息通讯我没有测试过,这个在项目中是不可取的,不过这里我们就是做一个如何来使用这个GameKit的工具,如何实现这个过程,先感受一下,看下面的代码吧:

GameKitHelperViewController.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//
// GameKitHelperViewController.h
// Simple GameKit
//
// Created by david on 13-8-22.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "GameKitHelper.h"

@interface GameKitHelperViewController : UIViewController<GameKitHelperDataDelegate,UITextViewDelegate>
@property (strong, nonatomic) IBOutlet UITextView *sendView;
@property (strong, nonatomic) IBOutlet UITextView *receviceView;

@end

GameKitHelperViewController.m

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
71
72
73
74
75
76
77
//
// GameKitHelperViewController.m
// Simple GameKit
//
// Created by david on 13-8-22.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import "GameKitHelperViewController.h"
#define COOKBOOK_PURPLE_COLOR [UIColor colorWithRed:0.20392f green:0.19607f blue:0.61176f alpha:1.0f]


@interface GameKitHelperViewController ()

@end

@implementation GameKitHelperViewController
@synthesize sendView;
@synthesize receviceView;

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

self.navigationController.navigationBar.tintColor = COOKBOOK_PURPLE_COLOR;
self.navigationItem.leftBarButtonItem = BARBUTTON(@"Clear", @selector(clear));

[GameKitHelper sharedInstance].sessionID = @"Typing Together";
[GameKitHelper sharedInstance].dataDelegate = self;
[GameKitHelper assignViewController:self];
[sendView becomeFirstResponder];
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}


-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

}

#pragma mark - methods of textview
-(void) textViewDidChange:(UITextView *)textView
{
if(![GameKitHelper sharedInstance].isConnected)
{
return;
}

NSString *text = self.sendView.text;

if(!text || (text.length == 0))
{
text = @"clear";
}
NSData *textData = [text dataUsingEncoding:NSUTF8StringEncoding];
[GameKitHelper sendData:textData];
}

-(void) receivedData:(NSData *)data
{
NSString *text = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
receviceView.text = [text isEqualToString:@"clear"] ? @"" : text;
}

-(void) clear
{
sendView.text = @"";
}

@end

这里我是使用了storyboard,然后里面加了两个UITextView

首先要安装 Setuptools

1
2
wget --no-check-certificate https://pypi.python.org/packages/2.6/s/setuptools/setuptools-0.6c11-py2.6.egg
sudo sh ./setuptools-0.6c11-py2.6.egg

安装PIP

1
2
3
4
wget --no-check-certificate https://pypi.python.org/packages/source/p/pip/pip-1.4.tar.gz
tar -zxvf ./pip-1.4.tar.gz
cd pip-1.4
sudo python setup.py install

对于项目中,尤其是对于做web开发的话,页面的ajax的调用是少不了的,不过在使用django的框架的时候,已经很方便的提供了一个使用ajax 的库了,就是django-dajaxice,其如果安装都是很简单的,只要按照http://django-dajaxice.readthedocs.org/en/latest/installation.html这个说明进行安装,进行配置就好了,然后记得重新启动一下在运行就好了

往往会遇到这样的情况就是自己的static文件找不到,比如dajaxice.core.js这个文件找不到,千万不要试着去复制,那样是没有用的

只要记得同步一下static文件就好了

执行那个这个命令

1
python manage.py collectstatic

为了确定确实存在我们需要的文件,建议执行一下这个命令

1
python ./manage.py findstatic dajaxice/dajaxice.core.js

如果输出这个结果

1
2
Found 'dajaxice/dajaxice.core.js' here:
/tmp/tmpusCiQ2

说明这个文件是存在,那么执行上面的命令就没有什么问题啦

这里我将自己的示例代码贴一下

ajax.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#! -*- coding=utf-8 -*-
from django.utils import simplejson
from dajaxice.decorators import dajaxice_register

@dajaxice_register
def sayhello(request):
return simplejson.dumps({'message':'Hello World'})

@dajaxice_register
def feeling(request):
return simplejson.dumps({'message':'有感觉加1'})

@dajaxice_register
def no_feeling(request):
return simplejson.dumps({'message':'没有感觉加1'})

home.html

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
{% extends "base.html" %}
{% load staticfiles %}
{% load dajaxice_templatetags %}

{% block title %}享受购物的感觉{% endblock %}

{% block css %}
<link rel="stylesheet" href="{% static "waterfall/css/reset.css" %}">
<link rel="stylesheet" href="{% static "waterfall/css/waterfall.css" %}">
{% endblock %}

{% block content %}
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">

<div id='container'>
{% if items_woman %}
{% for item in items_woman %}
<div class="item" >
<a target='_blank' title='{{ item.title }}' href='{{ item.url_address }}'>
<img src="{{ MEDIA_URL }}{{ item.large_image }}" width="192" height="288">
</a>
<h3>{{ item.title|slice:"10" }}</h3>
<p>{{ item.description|slice:"100" }}</p>
<p>
<a class="btn btn-primary" target='_blank' href="{{ item.url_address }}">浏览</a>
<a class="btn have_feeling" href="#" onclick="Dajaxice.walkerfree.feeling(feeling_callback);">有感觉</a>
<a class="btn no_feeling" href="#" onclick="Dajaxice.walkerfree.no_feeling(no_feeling_callback);">没感觉</a>
<input type='hidden' value='woman' name='type'>
</p>
</div>
{% endfor %}
{% endif %}

{% if items_man %}
{% for item in items_man %}
<div class="item" >
<a target='_blank' title='{{ item.title }}' href='{{ item.url_address }}'>
<img src="{{ MEDIA_URL }}{{ item.large_image }}" width="192" height="288">
</a>
<h3>{{ item.title|slice:"10" }}</h3>
<p>{{ item.description|slice:"100" }}</p>
<p>
<a class="btn btn-primary" target='_blank' href="{{ item.url_address }}">浏览</a>
<a class="btn have_feeling" href="#" onclick="Dajaxice.walkerfree.feeling(feeling_callback);">有感觉</a>
<a class="btn no_feeling" href="#" onclick="Dajaxice.walkerfree.no_feeling(no_feeling_callback);">没感觉</a>
<input type='hidden' value='man' name='type'>
</p>
</div>
{% endfor %}
{% endif %}

{% if items_gifts %}
{% for item in items_gifts %}
<div class="item" >
<a target='_blank' title='{{ item.title }}' href='{{ item.url_address }}'>
<img src="{{ MEDIA_URL }}{{ item.large_image }}" width="192" height="288">
</a>
<h3>{{ item.title|slice:"10" }}</h3>
<p>{{ item.description|slice:"100" }}</p>
<p>
<a class="btn btn-primary" target='_blank' href="{{ item.url_address }}">浏览</a>
<a class="btn have_feeling" href="#" onclick="Dajaxice.walkerfree.feeling(feeling_callback);">有感觉</a>
<a class="btn no_feeling" href="#" onclick="Dajaxice.walkerfree.no_feeling(no_feeling_callback);">没感觉</a>
<input type='hidden' value='gifts' name='type'>
</p>
</div>
{% endfor %}
{% endif %}
</div>
</div>
</div>
</div>
{% block js %}

<script type='text/javascript' src="{% static "waterfall/js/libs/handlebars/handlebars.js" %}"></script>
<script type='text/javascript' src="{% static "waterfall/js/waterfall.min.js" %}"></script>
<script>
$('#container').waterfall({
itemCls: 'item',
colWidth: 210,
gutterWidth: 15,
gutterHeight: 15,
checkImagesLoaded: false,
dataType: 'html',
path: function(page) {
return 'data/data.html?page=' + page;
}
});
</script>
{% dajaxice_js_import %}
<script>
function my_js_callback(data){
alert(data.message);
}
function feeling_callback(data){
alert(data.message);
}
function no_feeling_callback(data){
alert(data.message);
}
</script>
{% endblock %}

{% endblock %}

关于Django的分页处理

后端逻辑操作是这样的:

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
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from man.models import Man

def home(request):
if request.user.is_authenticated():
user = request.user;
else:
user = request.user;
items_mans = Man.objects.filter(is_show=0).order_by('-create_date').all()
paginator_man = Paginator(items_mans,8)
page = request.GET.get('page',1)
try:
items_man = paginator_man.page(page)
except PageNotAnInteger:
items_man = paginator_man.page(1)
except EmptyPage:
items_man = paginator_man.page(paginator_man.num_pages)

return render_to_response('man/home.html',{
'action':'man',
'items_man':items_man,
'user':user
})

前端的页面处理是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div class="row-fluid">
<div class="span12">
<div class="pagination pagination-centered">
<ul>
{% if items_man.has_previous %}
<li>
<a href="?page={{ items_man.previous_page_number }}">上一页</a>
</li>
{% endif %}
<li class='disabled'>
<a class="">
{{ items_man.number }} / {{ items_man.paginator.num_pages }}
</a>
</li>
{% if items_man.has_next %}
<li>
<a href="?page={{ items_man.next_page_number }}">下一页</a>
</li>
{% endif %}
</ul>
</div>
</div>
</div>

对于提交的苹果官方的app,在审核的时候会给我们一些crash文件,对于这些有用的文件,里面是关于我们的bug的一些信息,那么该如何去调试呢
第一步:在任意目录创建一个目录,用来调试crash,我这里创建一个crash目录
第二步:将之前Archive的文件copy到crash目录里面

其中包括两个文件.app和.app.dSYM

如果找不到的话可以按照下面的步骤进行

先到Organizer

1,找到提交那个时刻的Archive文件,选中,show in Finder

2,然后到达这里,然后再选中红色区域,会出现3中所示的提示

3,ok显示包内容,然后自己找找吧,肯定会有的

copy就好了

第三步:将symbolicatecrash工具copy到crash目录

找不到这个文件可以去

1
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKit.framework/Versions/A/Resources

这里看看,应该就会有了。

第四步:将要调试的crash文件copy到crash目录

这个crash文件,这里是来自苹果官方的,其实有时候也是来自其他的用户的电脑上的。
第五步:通过命令进行测试
打开终端,转到crash目录
执行如下命令:

1
2
./symbolicatecrash ./2013-08-16-035933_DLiPad.crash ./appname.app.dSYM > symbol.crash
cat ./symbol.crash

结果如下:

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
Incident Identifier: 5434D911-E207-4D79-9139-40EA4EA76B45
CrashReporter Key: d11ed3a4adbb0d9ca4d6016e73e439640f95f289
Hardware Model: xxx
Process: appname [8158]
Path: /var/mobile/Applications/2AB1E8EB-6ECE-44F4-8195-4042339DD359/appname.app/appname
Identifier: appname
Version: ??? (???)
Code Type: ARM (Native)
Parent Process: launchd [1]

Date/Time: 2013-08-16 03:59:33.513 +0800
OS Version: iOS 6.1.3 (10B329)
Report Version: 104

Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Crashed Thread: 0

Last Exception Backtrace:
0 CoreFoundation 0x3126029e 0x3119e000 + 795294
1 libobjc.A.dylib 0x3910497a 0x390fc000 + 35194
2 UIKit 0x333f537c 0x33065000 + 3736444
3 UIKit 0x3323758e 0x33065000 + 1910158
4 UIKit 0x330c079c 0x33065000 + 374684
5 UIKit 0x33068c34 0x33065000 + 15412
6 UIKit 0x330686c8 0x33065000 + 14024
7 UIKit 0x33068116 0x33065000 + 12566
8 GraphicsServices 0x34d5c59e 0x34d56000 + 26014
9 GraphicsServices 0x34d5c1ce 0x34d56000 + 25038
10 CoreFoundation 0x3123516e 0x3119e000 + 618862
11 CoreFoundation 0x31235112 0x3119e000 + 618770
12 CoreFoundation 0x31233f94 0x3119e000 + 614292
13 CoreFoundation 0x311a6eb8 0x3119e000 + 36536
14 CoreFoundation 0x311a6d44 0x3119e000 + 36164
15 UIKit 0x330bf480 0x33065000 + 369792
16 UIKit 0x330bc2fc 0x33065000 + 357116
17 appname 0x000cf358 0xce000 + 4952
18 libdyld.dylib 0x3953bb1c 0x3953a000 + 6940


Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x39602350 __pthread_kill + 8
1 libsystem_c.dylib 0x3957911e pthread_kill + 54
2 libsystem_c.dylib 0x395b596e abort + 90
3 libc++abi.dylib 0x38b53d4a abort_message + 70
4 libc++abi.dylib 0x38b50ff4 default_terminate() + 20
5 libobjc.A.dylib 0x39104a74 _objc_terminate() + 144
6 libc++abi.dylib 0x38b51078 safe_handler_caller(void (*)()) + 76
7 libc++abi.dylib 0x38b51110 std::terminate() + 16
8 libc++abi.dylib 0x38b52594 __cxa_rethrow + 84
9 libobjc.A.dylib 0x391049cc objc_exception_rethrow + 8
10 CoreFoundation 0x311a6f1c CFRunLoopRunSpecific + 452
11 CoreFoundation 0x311a6d44 CFRunLoopRunInMode + 100
12 UIKit 0x330bf480 -[UIApplication _run] + 664
13 UIKit 0x330bc2fc UIApplicationMain + 1116
14 appname 0x000cf358 0xce000 + 4952
15 libdyld.dylib 0x3953bb1c start + 0

Thread 1:
0 libsystem_kernel.dylib 0x39602d98 __workq_kernreturn + 8
1 libsystem_c.dylib 0x39550cf6 _pthread_workq_return + 14
2 libsystem_c.dylib 0x39550a12 _pthread_wqthread + 362
3 libsystem_c.dylib 0x395508a0 start_wqthread + 4

Thread 2 name: Dispatch queue: com.apple.libdispatch-manager
Thread 2:
0 libsystem_kernel.dylib 0x395f2648 kevent64 + 24
1 libdispatch.dylib 0x39522974 _dispatch_mgr_invoke + 792
2 libdispatch.dylib 0x39522654 _dispatch_mgr_thread$VARIANT$mp + 32

Thread 3:
0 libsystem_kernel.dylib 0x39602d98 __workq_kernreturn + 8
1 libsystem_c.dylib 0x39550cf6 _pthread_workq_return + 14
2 libsystem_c.dylib 0x39550a12 _pthread_wqthread + 362
3 libsystem_c.dylib 0x395508a0 start_wqthread + 4

Thread 4 name: WebThread
Thread 4:
0 libsystem_kernel.dylib 0x395f1eb4 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x395f2048 mach_msg + 36
2 CoreFoundation 0x31235040 __CFRunLoopServiceMachPort + 124
3 CoreFoundation 0x31233d9e __CFRunLoopRun + 878
4 CoreFoundation 0x311a6eb8 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x311a6d44 CFRunLoopRunInMode + 100
6 WebCore 0x37196500 RunWebThread(void*) + 440
7 libsystem_c.dylib 0x3955b30e _pthread_start + 306
8 libsystem_c.dylib 0x3955b1d4 thread_start + 4

Thread 0 crashed with ARM Thread State (32-bit):
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x3b0f8534
r4: 0x00000006 r5: 0x3b0f8b88 r6: 0x1d844f24 r7: 0x2fd329f4
r8: 0x1d844f00 r9: 0x00000300 r10: 0x334de04b r11: 0x1c535350
ip: 0x00000148 sp: 0x2fd329e8 lr: 0x39579123 pc: 0x39602350
cpsr: 0x00000010
......

再执行如下命令:

1
dwarfdump --lookup 0x000cf358 --arch armv7 appname.app.dSYM/

关键是在这里0x000cf358,他是来自这里的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
0   libsystem_kernel.dylib            0x39602350 __pthread_kill + 8
1 libsystem_c.dylib 0x3957911e pthread_kill + 54
2 libsystem_c.dylib 0x395b596e abort + 90
3 libc++abi.dylib 0x38b53d4a abort_message + 70
4 libc++abi.dylib 0x38b50ff4 default_terminate() + 20
5 libobjc.A.dylib 0x39104a74 _objc_terminate() + 144
6 libc++abi.dylib 0x38b51078 safe_handler_caller(void (*)()) + 76
7 libc++abi.dylib 0x38b51110 std::terminate() + 16
8 libc++abi.dylib 0x38b52594 __cxa_rethrow + 84
9 libobjc.A.dylib 0x391049cc objc_exception_rethrow + 8
10 CoreFoundation 0x311a6f1c CFRunLoopRunSpecific + 452
11 CoreFoundation 0x311a6d44 CFRunLoopRunInMode + 100
12 UIKit 0x330bf480 -[UIApplication _run] + 664
13 UIKit 0x330bc2fc UIApplicationMain + 1116
14 应用的名称 0x000cf358 0xce000 + 4952
15 libdyld.dylib 0x3953bb1c start + 0

结果如下:

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
----------------------------------------------------------------------
File: appname.app.dSYM/Contents/Resources/DWARF/appname (armv7)
----------------------------------------------------------------------
Looking up address: 0x00000000000cf358 in .debug_info... found!

0x0015d390:
Compile Unit: length = 0x00001fc6 version = 0x0002 abbr_offset =
0x00000000 addr_size = 0x04 (next CU at 0x0015f35a)

0x0015d39b: TAG_compile_unit [1] *
AT_producer( "Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)" )
AT_language( DW_LANG_ObjC )
AT_name( "/Users/zhy/Downloads/ios/xxx/xxx/library/ASIHttpRequest/ASIDownloadCache.m" )
AT_low_pc( 0x000ccfc0 )
AT_stmt_list( 0x0002cf0b )
AT_comp_dir( "/Users/zhy/Downloads/ios/vlink_app_xunyi" )
AT_APPLE_major_runtime_vers( 0x02 )

0x0015dd38: TAG_subprogram [53] *
AT_name( "-[ASIDownloadCache isCachedDataCurrentForRequest:]" )
AT_decl_file( "/Users/zhy/Downloads/ios/xxx/xxx/library/ASIHttpRequest/ASIDownloadCache.m" )
AT_decl_line( 315 )
AT_prototyped( 0x01 )
AT_type( {0x0015d490} ( BOOL ) )
AT_APPLE_isa( 0x01 )
AT_low_pc( 0x000cf278 )
AT_high_pc( 0x000cf9e2 )
AT_frame_base( r7 )
AT_object_pointer( {0x0015dd54} )

0x0015dd86: TAG_lexical_block [10] *
AT_low_pc( 0x000cf2ca )
AT_high_pc( 0x000cf9de )
Line table dir : '/Users/zhy/Downloads/ios/xxx/xxx/library/ASIHttpRequest'
Line table file: 'ASIDownloadCache.m' line 320, column 3 with start address 0x00000000000cf340

Looking up address: 0x00000000000cf358 in .debug_frame... found!

0x00007290: FDE
length: 0x0000000c
CIE_pointer: 0x00000000
start_addr: 0x000cf278 -[ASIDownloadCache isCachedDataCurrentForRequest:]
range_size: 0x0000076a (end_addr = 0x000cf9e2)
Instructions: 0x000cf278: CFA=4294967295+4294967295

到这里就知道问题所在了吧

1
2
Line table dir : '/Users/zhy/Downloads/ios/xxx/xxx/library/ASIHttpRequest'
Line table file: 'ASIDownloadCache.m' line 320, column 3 with start address 0x00000000000cf340

如果有多个crash文件的话,可以重复操作一遍就好了。

第一步:创建应用

1
python manage.py startapp accounts

第二步:url规则添加

1
2
3
4
5
#用户的处理中心
url(r'^accounts/$','accounts.views.index',name='accounts_home'),
url(r'^accounts/register$','accounts.views.register',name='accounts_register'),
url(r'^accounts/login$','accounts.views.login',name='accounts_login'),
url(r'^accounts/logout$','accounts.views.logout',name='accounts_logout'),

第三步:action的添加

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
#!-*- coding=utf-8 -*-

'''
用户中心
'''
def home(request):
pass

'''
用户注册页
'''
def register(request):
pass

'''
用户登录页
'''
def login(request):
pass

'''
用户注销页accounts
'''
def logout(request):
pass

第四步:template文件(模板文件的添加)的添加
注册页面(这个页面根据自己的需求定义,项目不同,设计不同)

登录页面(这个页面根据自己的需求定义,项目不同,设计不同)

个人中心(这个页面根据自己的需求定义,项目不同,设计不同)

第五步:完善action

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!-*- coding=utf-8 -*-
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from django import forms
from django.contrib.auth import authenticate, login as auth_login, logout as auth_logout
from django.contrib.messages import constants as messages
from django.contrib import messages
from django.contrib.auth.models import User



def home(request):
'''用户中心'''
if request.user.is_authenticated():
user = request.user;
else:
user = request.user;
return render_to_response('accounts/home.html',{'user':user},context_instance=RequestContext(request));

def register(request):
'''用户注册页'''
template_var = {}
form = RegisterForm()
if request.method=="POST":
form=RegisterForm(request.POST.copy())
if form.is_valid():
username = form.cleaned_data["username"]
email = form.cleaned_data["email"]
password = form.cleaned_data["password"]
repassword = form.cleaned_data["repassword"]
if password != repassword:
return HttpResponse('重复登录密码与登录密码不一致');
user = User.objects.create_user(username, email, password)
user.save()
validate_login(request, email, password)
return HttpResponseRedirect(reverse("accounts_home"))
return render_to_response('accounts/register.html',{'form':form},context_instance=RequestContext(request));

def validate_login(request, username, password):
'''验证用户登录'''
return_value = False
user = authenticate(username=username,password=password)
if user:
if user.is_active:
auth_login(request,user)
return_value = True
else:
messages.add_message(request, messages.INFO, _(u'此账户尚未激活,请联系管理员'))
else:
messages.add_message(request, messages.INFO, _(u'此账户不存在,请联管理员'))

return return_value

def login(request):
'''用户登录页'''
template_var = {}
form = LoginForm()
if request.method == "POST":
form = LoginForm(request.POST.copy())
if form.is_valid():
validate_login(request, form.cleaned_data["username"], form.cleaned_data["password"])
return HttpResponseRedirect(reverse('accounts_home'))
template_var["form"] = form
return render_to_response('accounts/login.html', template_var, context_instance=RequestContext(request));


def logout(request):
'''用户注销页'''
auth_logout(request)
return HttpResponseRedirect(reverse('home'))

class LoginForm(forms.Form):
username=forms.CharField(label=_(u"登录账号"), widget=forms.TextInput(attrs={'placeholder':'登录账号','class':'input-block-level'}))

password=forms.CharField(label=_(u"登录密码"),
widget=forms.PasswordInput(attrs={'placeholder':'登录密码','class':'input-block-level'}))

class RegisterForm(forms.Form):
'''注册表单'''
username=forms.CharField(label=_(u"登录账号"), widget=forms.TextInput(attrs={'placeholder':'登录账号','class':'input-block-level'}))
email=forms.EmailField(label=_(u"邮件地址"), widget=forms.TextInput(attrs={'placeholder':'登录邮箱','class':'input-block-level'}))
password=forms.CharField(label=_(u"登录密码"), widget=forms.PasswordInput(attrs={'placeholder':'登录密码','class':'input-block-level'}))
repassword=forms.CharField(label=_(u"重复登录密码"), widget=forms.PasswordInput(attrs={'placeholder':'重复登录密码','class':'input-block-level'}))

def clean_username(self):
'''验证昵称'''
username = User.objects.filter(username__iexact=self.cleaned_data["username"])
if not username:
return self.cleaned_data["username"];
raise forms.ValidationError(_(u"该昵称已经被使用"));

def clean_email(self):
'''验证email'''
email = User.objects.filter(email__iexact=self.cleaned_data["email"])
if not email:
return self.cleaned_data["email"];
raise forms.ValidationError(_(u"改邮箱已经被使用"));
0%