Push Notification, Step by Step Setup.

坑爹的苹果,居然在提交证书的时候,由于浏览器(自家的Safari)的问题导致提交不成功,换成别的浏览器才成功。
The device token for Development and for Production is DIFFERENT!

(!!! DO NOT use the Safari, When access the develop.apple.com)
1.Access the certificate for push notification
1.获取用于推送通知的证书

1.1.Request 2 certificate from the KeyChain Assistant (CSR), one for develop, one for production. If you do not know how to do it, see Instruction 1.4 below. And export the associated Private Key as .p12 files. So after this step, we get 4 files.
1.1.从证书助手获取两个证书,一个在开发中使用,一个在发布的产品中使用(详见1.4中的系统提示)

1.2.On developer.apple.com in the Provisioning Portal, Select the App Id that you want to enable Push Notification, and click the ‘Config’ button.
1.2.在developer.apple.com的Provisioning Portal中,选择要发送推送通知的App Id,点击“Config”按钮

1.3.Check the Enable Push Notification Check box
1.3.勾上Enable Push Notification多选框

1.4.Click the ‘Config’ button for develop, and there is a guide for ‘How to request a certificate from KeyChain Assistant’. When you’ve done, click the ‘Continue’.
1.4.点击开发对应的’Config’,然后回出来一个向导告诉你如何生成CSR文件

1.5.Select the CSR file that generated by last step, then click ‘Generate’. (In this step, DO NOT use the Safari, or the ‘generate’ button will not response to your click at all……)
1.5.在最后一步,选择生成的CSR文件,然后点击‘Generate’。(坑爹的就是Safari下这个按钮点了没有任何效果,换别的浏览器就好了,汗···)

1.6.Download the generated certificate and install on your server.(On mac, just double click the certificate)
1.6.下载生成的证书并且双击它进行安装

1.7.Do the same for Production, following step 1.4,1.5,1.6.
1.7.对于发布版本,按照1.4, 1.5 和1.6的步骤再来一次。

2.Build the .pem file for our server to connect to APNS.
2.生成用来从服务器连接APNS的PEM文件

2.1.Copy the .p12, .csr, .cer files together in one place.
2.1.将前面得到的.p12, .csr, .cer文件放在一起。这时一共有6个文件,对应Develop,比如叫做dev.p12,dev.csr,dev.cer;对于发布有另外三个文件,这里以dev为例

2.2.Convert the dev.cer into devCer.pem. In the terminal, run

openssl x509 -in dev.cer -inform der -out devCer.pem

2.2.把dev.cer转换成devCer.pem。打开终端,运行

openssl x509 -in dev.cer -inform der -out devCer.pem

2.3.Conver the dev.p12 into devKey.pem. In the terminal, run openssl pkcs12 -nocerts -out devKey.pem -in dev.p12. First you will be asked to input the password for the dev.p12 file, and then will let you input your password for devKey.pem file.
2.3.把dev.p12转换成devKey.pem. 在终端中运行 openssl pkcs12 -nocerts -out devKey.pem -in dev.p12。中间会让你首先输入.p12文件的密码,然后让你输入密码来保护生成的.pem文件

2.4.Combine the two pem file together. In the terminal, run

cat devCer.pem devKey.pem > dev.pem

2.4.把两个pem文件合成一个。运行

cat devCer.pem devKey.pem > dev.pem

2.5.Then we can test if things goes well. By run

telnet gateway.sandbox.push.apple.com 2195

to see if you can reach the APNS. Then run

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert devCer.pem -key devKey.pem

to see if the two pem files are ok.
2.5.然后我们可以测试一下是否一切都正常。先运行

telnet gateway.sandbox.push.apple.com 2195

确定可以连接到APNS,然后运行

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert devCer.pem -key devKey.pem

看看pem文件是不是ok的。

3.Setup the application project in xCode.
3.在xCode中配置应用程序

3.1.Open the application project in xCode, and code sign with the specific (the exact same bundle id) provisioning file. If you want debug the push notification in xCode, be sure the right develop provisioning file is used.
3.1.在code sign部分,选择正确的provisioning file

3.2.Add some code to enable push notification in your application as:
3.2.在app delegate中添加以下代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
    //Some other code here ... for the window or something.
    return YES;
}
#pragma mark notification
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"Failed to Get Token, Error: %@", error);
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    NSLog(@"Success Get Token : %@", deviceToken);
}

3.3.Run your application in the real device, not simulator(the simulator is not support the push notification)
3.3.在真机上运行应用程序(模拟器是不支持推送的,也无法测试)

3.4.If you get the log of “Failed to Get Token”, then you must have something wrong in the previous steps.
3.4.如果发现输出了”Failed to Get Token”,说明前面步骤上有问题。

3.5.Else you will get a log like : “Success Get Token : <90757852 {6 segment of this kind of hex numbers} 82728ad7>“, record this deviceToken, which will be used for testing.
3.5.正常情况下,你可以获得一条消息”Success Get Token : <90757852 {6 segment of this kind of hex numbers} 82728ad7>“,记录下这段deviceToken,后面的测试会用到它

3.6.On your device, there will be an alert to ask permission for push notification, tap on ‘OK’
3.6.在第一次运行的时候,应该会有系统的alert让你允许推送通知,点’OK’就行。

4.Test the Push Notification For Development
4.然后就可以测试一下推送了。

4.1.paste the following code in to testPush.php file
4.1.把下面这段代码保存为testPush.php文件

 $message,
    'sound' => 'default'
    );

// Encode the payload as JSON
$payload = json_encode($body);

// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;

// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));

if (!$result)
    echo 'Message not delivered' . PHP_EOL;
else
    echo 'Message successfully delivered' . PHP_EOL;

// Close the connection to the server
fclose($fp);

4.2.Modify the variables at the first few lines according to your situation. The deviceToken will be used here.
4.2.修改文件最开始的几个变量。这里会用到你刚才记录下的deviceToken。

4.3.Running the php code.
4.3.运行一下这段php代码。

php testPush.php

Reference:
http://www.raywenderlich.com/3443/apple-push-notification-services-tutorial-part-12
http://article.ityran.com/archives/194
http://www.cocoachina.com/applenews/devnews/2012/1212/5312.html

【转】iOS开发中的UITableView编辑模式

文章写得很好,转载自:http://my.oschina.net/plumsoft/blog/53271

这篇文章主要讲的表格的操作包括:标记行、移动行、删除行、插入行。

这次就不从头建立工程了,在http://www.oschina.net/code/snippet_164134_9876下载工程。这个工程就是最简单的产生一个表格并向其中写入数据。用Xcode 4.2打开它,在这个工程基础上实现以上操作。

1、标记行

这里讲的标记行指的是单击此行,可以实现在此行右边出现一个勾,如下图所示:

为了实现标记功能,在ViewController.m中@end之前添加代码:

#pragma mark -
#pragma mark Table Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *oneCell = [tableView cellForRowAtIndexPath: indexPath];
    if (oneCell.accessoryType == UITableViewCellAccessoryNone) {
        oneCell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else 
        oneCell.accessoryType = UITableViewCellAccessoryNone;
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
}

该代码实现:单击某行时,若此行未被标记,则标记此行;若此行已经被标记,则取消标记。

运行效果如上图。

上面的代码实际上就是修改某行的accessoryType属性,这个属性可以设为四个常量:

UITableViewCellAccessoryCheckmark
UITableViewCellAccessoryDetailDisclosureButton
UITableViewCellAccessoryDisclosureIndicator
UITableViewCellAccessoryNone

效果依次如下图所示:

            

   UITableViewCellAccessoryCheckmark            UITableViewCellAccessoryDetailDisclosureButton

                

UITableViewCellAccessoryDisclosureIndicator                   UITableViewCellAccessoryNone

注意,上面第二张图片中的蓝色圆圈不仅仅是一个图标,还是一个控件,点击它可以触发事件,在上一篇博客《iOS开发16:使用Navigation Controller切换视图》使用过。

2、移动行

想要实现移动或者删除行这样的操作,需要启动表格的编辑模式。使用的是setEditing:animated:方法。

2.1 打开ViewController.xib,将其中的表格控件映射成Outlet到ViewController.h,名称为myTableView。

2.2 打开ViewController.m,在viewDidLoad方法最后添加代码:

//启动表格的编辑模式
[self.myTableView setEditing:YES animated:YES];

2.3 在@end之前添加代码:

//打开编辑模式后,默认情况下每行左边会出现红的删除按钮,这个方法就是关闭这些按钮的
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
           editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return UITableViewCellEditingStyleNone; 
} 

//这个方法用来告诉表格 这一行是否可以移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 
    return YES; 
}

//这个方法就是执行移动操作的
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)
        sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
    NSUInteger fromRow = [sourceIndexPath row]; 
    NSUInteger toRow = [destinationIndexPath row]; 
    
    id object = [list objectAtIndex:fromRow]; 
    [list removeObjectAtIndex:fromRow]; 
    [list insertObject:object atIndex:toRow]; 
}

editingStyleForRowAtIndexPath这个方法中用到了常量UITableViewCellEditingStyleNone,它表示不可编辑,这里的编辑指的是删除和插入。表示表格行的编辑模式的常量有:

UITableViewCellEditingStyleDelete
UITableViewCellEditingStyleInsert
UITableViewCellEditingStyleNone

顾名思义,第一个表示删除,第二个表示插入,第三个表示不可编辑。

若将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleNone依次换成上面三个值,则它们运行的效果依次如下图所示:

     

2.4 运行,从下图可以看到实现了行的移动:

但是也会发现,现在无法对每行进行标记了。这说明,在编辑模式下,无法选择行,从而didSelectRowAtIndexPath这个方法不会执行。

3、删除行

从第2步过来,实现删除某行,其实比较简单了。

3.1将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleNone修改成UITableViewCellEditingStyleDelete。

3.2 在@end之前添加代码:

//这个方法根据参数editingStyle是UITableViewCellEditingStyleDelete
//还是UITableViewCellEditingStyleDelete执行删除或者插入
- (void)tableView:(UITableView *)tableView commitEditingStyle:
    (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger row = [indexPath row];
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [self.list removeObjectAtIndex:row]; 
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                         withRowAnimation:UITableViewRowAnimationAutomatic]; 
    }
}

在这个方法中又出现了一个常量:UITableViewRowAnimationAutomatic,它表示删除时的效果,类似的常量还有:

UITableViewRowAnimationAutomatic
UITableViewRowAnimationTop
UITableViewRowAnimationBottom
UITableViewRowAnimationLeft
UITableViewRowAnimationRight
UITableViewRowAnimationMiddle
UITableViewRowAnimationFade
UITableViewRowAnimationNone

它们的效果就不一一介绍了,可以在实际使用时试试。

3.3 运行,看看效果:

     

刚运行时显示如左边的图片,点击某一行左边的圆圈图标,会显示如中间图片所示。然后点击Delegate按钮,那一行就会被删除掉,如右边的那张图片所示,它显示的是删除时的效果。

4、插入行

这个与删除行类似。

4.1 首先将editingStyleForRowAtIndexPath方法中的UITableViewCellEditingStyleDelete修改成UITableViewCellEditingStyleInsert。

4.2在3.2添加的方法中添加代码:

else {
    //我们实现的是在所选行的位置插入一行,因此直接使用了参数indexPath
    NSArray *insertIndexPaths = [NSArray arrayWithObjects:indexPath,nil];
    //同样,将数据加到list中,用的row
    [self.list insertObject:@"新添加的行" atIndex:row];
    [tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationRight];
}

上面的代码中也可以不用insertRowsAtIndexPaths方法,而直接使用[tableView reloadData];语句,但是这样就没有添加的效果了。

4.3 好了,运行一下:

     

刚运行时如上面左图所示,单击了某个加号后,新的一行就从右边飞进来了,因为在insertRowsAtIndexPaths中用了参数UITableViewRowAnimationRight。

 

ARC – Automatic Reference Counting in iOS Development

ARC帮我们做了很多事情,主要的几点如下:

1·自动生成dealloc函数,帮我们释放对象中的变量
2·如果你要自己写dealloc,它会帮你加上[super dealloc];
3·AutoreleasePool用@autoreleasepool{}的block代替
4·weak修饰符,在所指对象被释放后自动置为nil,cool!



参考(Ref.)
https://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

Why we use ‘copy’ attribute for NSString property?

@interface AClass:NSObjet
@property (nonatomic, copy) NSString* aStrProperty;
@end

Like the code above, we use ‘copy’ instead of ‘retain’ attribute in the NSString property. For the reason, is that we do not want the original NSString object to be modified in this class.
像上面这段代码,为什么要用copy而不是retain呢?因为我们不希望外面的字符串在不经意间由这个类的对象修改。

But for that a NSString cannot be modified, why not using the ‘retain’ instead of ‘copy’? Because, one can also assign the aStrProperty with a NSMutableString instead of NSString. Thus, ‘copy’ is more safe than ‘retain’.
可是,既然NSString是不可以被修改的,为什么还有这个担忧呢?因为虽然NSString不可修改,可是使用者完全可能将一个NSMutableString传递给aStrProperty,然后在类方法里修改它的内容,这不是我们希望出现的,所以采用copy。

Access to ‘class’ Tag Attribute in HTML using HtmlDocumentElement in C#

<p class="aClass">some content</p>

像上面这一段html代码,在用HtmlDocumentElement进行处理的时候,用直观的

element.getAttribute("class");

是得不到class属性的值”aClass”的,原因是IE用className代替了class。

所以要想得到class属性,需要这么做:

element.getAttribute("className");

参考:http://zhidao.baidu.com/question/208025778.html