Xmppstream

Posted by Kimziv at 2013-07-26 with tags

client下线

<presence type="unavailable">  
<status>Logged out</status>  
</presence>  

client发起连接

<?xml version="1.0"?>  
<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="xumatomacbook-pro.local" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">  

server相应并回复验证的features

<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='xumatomacbook-pro.local' id='675c6847-c13d-4710-9844-d9339e4df087' version='1.0' xml:lang='en'>  

<stream:features>  
<ver xmlns="urn:xmpp:features:rosterver"/>  
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>  
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">  
<mechanism>PLAIN</mechanism>  
<mechanism>ANONYMOUS</mechanism>  
</mechanisms>  
<register xmlns="http://jabber.org/features/iq-register"/>  
<auth xmlns="http://jabber.org/features/iq-auth"/>  
</stream:features>  

client启动tls验证

<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>  

server表示支持,可以继续

<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>  

tls验证结束,重新开始

<?xml version="1.0"?>  

<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="xumatomacbook-pro.local" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">  

server响应,并返回下一步验证支持的features,sasl

<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='xumatomacbook-pro.local' id='675c6847-c13d-4710-9844-d9339e4df087' version='1.0' xml:lang='en'>  


<stream:features>  
<ver xmlns="urn:xmpp:features:rosterver"/>  
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">  
<mechanism>PLAIN</mechanism>  
<mechanism>ANONYMOUS</mechanism>  
</mechanisms>  
<register xmlns="http://jabber.org/features/iq-register"/>  
<auth xmlns="http://jabber.org/features/iq-auth"/>  
</stream:features>  

client开始sasl验证

<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">AGd1YW5mZWkAZ3VhbmZlaQ==</auth>  

server表示成功了

<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>  

client重新开始

<?xml version="1.0"?>  


<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="xumatomacbook-pro.local" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">  

server响应并返回支持的features

<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='xumatomacbook-pro.local' id='675c6847-c13d-4710-9844-d9339e4df087' version='1.0' xml:lang='en'>  


<stream:features>  
<ver xmlns="urn:xmpp:features:rosterver"/>  
<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>  
<register xmlns="http://jabber.org/features/iq-register"/>  
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>  
</stream:features>  

client请求resource bind

<iq type="set" id="bind_1">  
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">  
<resource>Psi+</resource>  
</bind>  
</iq>  

server判断并返回结果

<iq xmlns="jabber:client" type="result" id="bind_1" to="guanfei@xumatomacbook-pro.local/Psi+">  
<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">  
<jid>guanfei@xumatomacbook-pro.local/Psi+</jid>  
</bind>  
</iq>  

client发起session

<iq type="set" id="ab46a">  
<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>  
</iq>  

server端响应

<iq type="result" id="ab46a" to="guanfei@xumatomacbook-pro.local/Psi+"/>  

####client端请求roster列表  
<iq type="get" id="ab47a">  
<query xmlns="jabber:iq:roster"/>  
</iq>  

server端返回

<iq type="result" id="ab47a" to="guanfei@xumatomacbook-pro.local/Psi+">  
<query xmlns="jabber:iq:roster">  
<item subscription="both" name="ohno" jid="guanfei1@xumatomacbook-pro.local"/>  
</query>  
</iq>  

client广播自己的出席信息

<presence>  
<priority>50</priority>  
<c xmlns="http://jabber.org/protocol/caps" node="http://psi-dev.googlecode.com/caps" ver="0.16" ext="ca cs e-time ep-notify-2 html last-act mr sxe whiteboard"/>  
</presence>  

client请求自己的个人信息

<iq type="get" id="ab49a">  
<query xmlns="jabber:iq:privacy"/>  
</iq>  

client请求bookmark

<iq type="get" id="ab4aa">  
<query xmlns="jabber:iq:private">  
<storage xmlns="storage:bookmarks"/>  
</query>  
</iq>  

client请求个人vcard

<iq type="get" to="guanfei@xumatomacbook-pro.local" id="ab4ba">  
<vCard xmlns="vcard-temp"/>  
</iq>  

client请求disco列表

<iq type="get" to="xumatomacbook-pro.local" id="ab4ca">  
<query xmlns="http://jabber.org/protocol/disco#info"/>  
</iq>  

server广播出席信息

<presence from="guanfei@xumatomacbook-pro.local/Psi+" to="guanfei@xumatomacbook-pro.local">  
<priority>50</priority>  
<c xmlns="http://jabber.org/protocol/caps" node="http://psi-dev.googlecode.com/caps" ver="0.16" ext="ca cs e-time ep-notify-2 html last-act mr sxe whiteboard"/>  
</presence>  

server返回个人信息项列表

<iq type="result" id="ab49a" to="guanfei@xumatomacbook-pro.local/Psi+">  
<query xmlns="jabber:iq:privacy">  
<list name="blocked"/>  
<default name="blocked"/>  
<active name="blocked"/>  
</query>  
</iq>  

client请求block项内容

<iq type="get" id="ab4da">  
<query xmlns="jabber:iq:privacy">  
<list name="blocked"/>  
</query>  
</iq>  

server返回bookmark信息

<iq type="result" id="ab4aa" to="guanfei@xumatomacbook-pro.local/Psi+">  
<query xmlns="jabber:iq:private">  
<storage xmlns="storage:bookmarks"/>  
</query>  
</iq>  

server返回vcard信息

<iq from="guanfei@xumatomacbook-pro.local" type="result" to="guanfei@xumatomacbook-pro.local/Psi+" id="ab4ba">  
<vCard xmlns="vcard-temp">  
<FN>guanfei</FN>  
<NICKNAME>guanfei</NICKNAME>  
</vCard>  
</iq>  

server返回disco列表

<iq from="xumatomacbook-pro.local" type="result" to="guanfei@xumatomacbook-pro.local/Psi+" id="ab4ca">  
<query xmlns="http://jabber.org/protocol/disco#info">  
<identity category="server" type="im" name="Tigase ver. 0.0.0-0"/>  
<feature var="http://jabber.org/protocol/disco#info"/>  
<feature var="http://jabber.org/protocol/disco#items"/>  
<feature var="msgoffline"/>  
<feature var="http://jabber.org/protocol/stats"/>  
<feature var="http://jabber.org/protocol/commands"/>  
<feature var="jabber:iq:version"/>  
<feature var="jabber:iq:roster"/>  
<feature var="jabber:iq:roster-dynamic"/>  
<feature var="vcard-temp"/>  
<feature var="urn:ietf:params:xml:ns:xmpp-sasl"/>  
<feature var="urn:xmpp:ping"/>  
<feature var="http://jabber.org/protocol/pubsub"/>  
<feature var="http://jabber.org/protocol/pubsub#owner"/>  
<feature var="http://jabber.org/protocol/pubsub#publish"/>  
<identity category="pubsub" type="pep"/>  
<feature var="urn:ietf:params:xml:ns:xmpp-session"/>  
<feature var="http://jabber.org/protocol/amp"/>  
<feature var="msgoffline"/>  
<feature var="http://jabber.org/protocol/disco#info"/>  
<feature var="http://jabber.org/protocol/disco#items"/>  
<feature var="jabber:iq:privacy"/>  
<feature var="urn:ietf:params:xml:ns:xmpp-bind"/>  
<feature var="jabber:iq:private"/>  
<feature var="jabber:iq:auth"/>  
</query>  
</iq>  

<presence from="guanfei1@xumatomacbook-pro.local/Psi+" to="guanfei@xumatomacbook-pro.local">  
<priority>50</priority>  
<c xmlns="http://jabber.org/protocol/caps" node="http://psi-dev.googlecode.com/caps" ver="0.16" ext="ca cs e-time ep-notify-2 html last-act mr sxe whiteboard"/>  
</presence>  

<iq type="result" id="ab4da" to="guanfei@xumatomacbook-pro.local/Psi+">  
<query xmlns="jabber:iq:privacy">  
<list name="blocked">  
<item action="allow" order="100"/>  
</list>  
</query>  
</iq>  
Top

为什么objc里用脱字符作为block标志符

Posted by Kimziv at 2013-07-25 with tags objective c, ^, block

问题如题。

答案:脱字符是c++里唯一一个没有被重载的运算符,所以苹果选择了这个定义Block,有一期wwdc里苹果的工程师讲的:wwdc2010 session 206

it's the only unary operator we knew of that could not be operator overloaded in C++, so ...

Top

如何解决国内安装gem的问题

Posted by Kimziv at 2013-07-19 with tags gem, 翻墙, ruby

几次在bash里执行gem install bundler 都会出现以下问题

ERROR:  Could not find a valid gem 'bundler' (>= 0), here is why:
      Unable to download data from https://rubygems.org/ - Errno::ETIMEDOUT: Operation timed out - connect(2) (https://rubygems.org/latest_specs.4.8.gz)
ERROR:  Possible alternatives: bundler

之前买的VPN又用完了,太让我失望了,国内的GFW,于是自己动手,丰衣足食,偶然发现国内还有一个淘宝gems mirror,废话少说,接下来告诉你怎么解决问题吧:

$ gem sources --remove https://rubygems.org/
$ gem sources -a http://ruby.taobao.org/
$ gem sources -l
*** CURRENT SOURCES ***

http://ruby.taobao.org
# 请确保只有 ruby.taobao.org
$ gem install rails

如果你是用 Bundle (Rails 项目)

source 'http://ruby.taobao.org/'
gem 'rails', '3.2.12'
...

Ruby源代码下载

RVM改用本站作为下载源, 提高 Ruby 安装速度

  • For Mac

    $ sed -i .bak 's!ftp.ruby-lang.org/pub/ruby!ruby.taobao.org/mirrors/ruby!' $rvm_path/config/db

  • For Linux

    $ sed -i 's!ftp.ruby-lang.org/pub/ruby!ruby.taobao.org/mirrors/ruby!' $rvm_path/config/db

附:淘宝 Ruby官方FTP镜像

经查明,由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败。所以你会与遇到 gem install rackbundle install 的时候半天没有响应,具体可以用 gem install rails -V 来查看执行过程。

Top

Blocks 取代 Delegates

Posted by Kimziv at 2013-06-18 with tags UIActionSheet, UIAlertView, Blocks, Delegate

Objective  C里Block介绍

Block和一个函数很像, 产生于一个叫做GCD的新功能,GCD用于同步处理环境下有更好的运行效率,Block把一个task封装好交给GCD,GCD在宏观上对其进行CPU和Memory等资源进行分配,Block一般长成这样:

^(args...)
{
    //代码
    ...
}

常用与方法回调和异步响应,在此之前使用Delegate和Protocal组合实现,编写代码的时候比较分散,比较麻烦。

UIActionSheet & UIAlertView Blocks的实现

对于我们常用的UIActionSheet和UIAlertView等控件都的Delegate方法可以改写成Block方式来实现,现在新建一个实现UIAlertSheet的Delegate Category:

  • 声明文件:UIActionSheet+Blocks.h

      #import <UIKit/UIKit.h>
      /*
      * Completion handler invoked when user taps a button.
      *
      * @param actionSheet The action sheet being shown.
      * @param buttonIndex The index of the button tapped.
      */
      typedef void(^UIActionSheetHandler)(UIActionSheet *actionSheet, NSInteger buttonIndex);
    
      /**
      * Category of `UIActionSheet` that offers a completion handler to listen to interaction. This avoids the need of the implementation of the delegate pattern.
      *
      * @warning Completion handler: Invoked when user taps a button.
      *
      * typedef void(^UIActionSheetHandler)(UIActionSheet *actionSheet, NSInteger buttonIndex);
      *
      * - *actionSheet* The action sheet view being shown.
      * - *buttonIndex* The index of the button tapped.
      */
      @interface UIActionSheet (Blocks) <UIActionSheetDelegate>
    
      /**
      * Shows the sheet from a view.
      *
      * @param view The view from which the action sheet originates.
      * @param handler The handler that will be invoked in user interaction.
      */
      - (void)showInView:(UIView *)view handler:(UIActionSheetHandler)handler;
      @end
    
  • 实现文件:UIActionSheet+Blocks.m

      #import "UIActionSheet+Blocks.h"
      #import <objc/runtime.h>
      /*
      * Runtime association key.
      */
      static NSString *kHandlerAssociatedKey = @"kHandlerAssociatedKey";
    
      @implementation UIActionSheet (Blocks)
    
      #pragma mark - Showing
    
      /*
      * Shows the sheet from a view.
      */
      - (void)showInView:(UIView *)view handler:(UIActionSheetHandler)handler {
    
          objc_setAssociatedObject(self, (__bridge const void *)(kHandlerAssociatedKey), handler, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
          [self setDelegate:self];
          [self showInView:view];
      }
      @end
    

如何使用?

UIActionSheet+Blocks 是UIActionSheet的子类,提供了完整的交互式侦听处理,避免使用委派设计模式实现。使用方法如下:

  1. 首先在你的类中引入UIActionSheet+Blocks.h ;
  2. 按照一下方式创建UIActionSheet;

     UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Test"
     // Can be another value but will be overridden when showing with handler.
                                                        delegate:nil 
                                               cancelButtonTitle:@"Cancel"
                                          destructiveButtonTitle:@"Delete"
                                               otherButtonTitles:@"Option 1", @"Option 2", nil];
    
  3. 用一下方法显示UIActionSheet,在名为handler的block中编写事件响应代码;

     [sheet showInView:view 
               handler:^(UIActionSheet *actionSheet, NSInteger buttonIndex) {
                   if (buttonIndex == [actionSheet cancelButtonIndex]) {
                       NSLog(@"Cancel button index tapped");
                   } else if (buttonIndex == [actionSheet destructiveButtonIndex]) {
                       NSLog(@"Destructive button index tapped");
                   } else  {
                       NSLog(@"Button %i tapped", buttonIndex);
                   }                      
     }];
    
  4. 对于其他show...方法,你也可以按照上面的方法进行改写:

    • (void)showInView:(UIView *)view handler:(UIActionSheetHandler)handler;
    • (void)showFromBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated handler:(UIActionSheetHandler)handler;
    • (void)showFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated handler:(UIActionSheetHandler)handler;
    • (void)showFromTabBar:(UITabBar *)view handler:(UIActionSheetHandler)handler;
    • (void)showFromToolbar:(UIToolbar *)view handler:(UIActionSheetHandler)handler;
Top

WWDC 2013 示例代码全部下载(附带视频下载)

Posted by Kimziv at 2013-06-17 with tags WWDC, videos, sample code

WWDC 2013已经结束了,虽然你没去成WWDC,但是你可以消化大牛们在WWDC上的演讲视频和sample code,是不是还要像往年一样,一个一个的下载代码呢,很遗憾的告诉你,这样的日子已经结束了,只要你注册了苹果开发者帐号,就可以下载所有的代码。

  • 下载代码,分两步

1.下载安装WWDC-Downloader

sudo gem install wwdcdownloader --no-rdoc --no-ri

2.在bash中运行命令,需要提供你的AppleID,下载到的文件夹可选,当没有提供时,默认下载到 wwdc2013-assets 文件中

wwdcdownloader <你的AppleID> [<下载到的文件夹>]
相关资源:

WWDC-Downloader项目链接

WWDC 2012 Videos And Sample Code Released

Free WWDC 2011 Videos Released

Free Development Videos From WWDC 2010

Top

Objective C Method Swizzling剖析

Posted by Kimziv at 2013-06-14 with tags method swizzling, objective c, 方法混合

一个例子

一个类SwizzlingDemo中两个方法method1和method2:

-(void)method1
{
    NSLog("method1 called");
}

-(void)method2
{
    NSLog("method2 called");
    [self method2];//注意,这里是递归调用method2
}

我在另一个方法test中使用SwizzlingDemo类中的方法:

-(void)test
{
    SwizzlingDemo sd=[[SwizzlingDemo alloc] init];
    [sd method1];
    MethodSwizzle([SwizzlingDemo class],
                    @selector(method1),
                    @selector(method2));
    [sd method1];
}

则输出:

method1 called
method2 called
method1 called

剖析

你是不是感觉很奇怪,当使用MethodSwizzle方法交换两个方法之后,本来以为会出现死循环的,结果却没有发生, 这是因为在Objc中,方法分为两部分:SEL和IMP两部分,Objc runtime会根据SEL去找它指向的实现代码,在使用MethodSwizzle方法之前

  • SEL(method1)->IMP(method1)
  • SEL(method2)->IMP(method2)

此时若依次调用method1和method2的话,则会陷入死循环;在使用MethodSwizzle方法之后

  • SEL(method1)->IMP(method2)
  • SEL(method2)->IMP(method1)

此时调用[sd method1]则实际上是执行method2实现中的代码:

NSLog("method2 called");
[self method2];//注意,这里是递归调用method2

而[sd method2]则执行的是method1中代码:

NSLog("method1 called");

所以会输出以上结果,而且不会出现死循环了。

Demo下载链接



[1] MethodSwizzle是一种在运行时修改方法名与方法实现映射关系的技术,常用于在系统内部方法的基础上增加新的处理流程,method_exchangeImplementations是runtime中常用的方法。

Top