windows平台把UliPad添加到右键菜单

葡京娱乐注册 1

      对.py文件支持右键用UliPad打开方式支持:

即时无异于糟我们将要讨论的凡动支付中比较重要之一律缠–网络要的封装.鉴于民用经验有限,本文将以自然水准达到参考
基于AFNetworking2.0和ReactiveCocoa2.1的iOS REST
Client,来以LeanCloud的Rest
Api来练手.前少节省的以身作则,我们还是应用由定义的PHP接口来当测试服务器,但是真实的服务器接口是涉及到多细节的,比如一个主导的权能控制机制,用户登录上等.为了能重新实在快速的起网络要求类的重构,本节选取一个境内较为常用之后端开发平台LeanCloud.
本文将落实一个所有真正数据的博客App的Demo,数据源取自博客主站:ios122.com.

  1.开辟注册表(win+R,运行约输入regedit)

整体代码示例下载: github

  2.先对*.py文件进行安装。找到注册表目录HKEY_CLASSES_ROOT\Python.File\shell,在shell文件夹图标上接触右侧键→新建→项,对新项进行命名,这里命啊叫
        字,在右键将会见显什么名字,比如自己的是“Edit with UliPad”。

以WP导出的XML数据易成JSON文件,导入LeanCloud.

先是,你是早晚使先失她官网注册一个账号,然后上加一个应用.这是自是补充加了利用iOS122.然晚新建一个曰也Post的Class,字段信息如下:

葡京娱乐注册 2

iOS122凡一个wordpress搭建的博客站点,导出的章为xml格式,需要处理成
LeanCloud
需要的JSON格式才能够导入,主站文章未多,几十篇,一个一个手动输,也是得的.我用试行着形容一有点截代码,来自动解析wp导出的文本,并根据需要转移对应的
JSON 文件.感兴趣的,可以友善试着干下!

  • 当即是旧的自wp中导出的主站的具有文章:
    http://ios122.bj.bcebos.com/Post.xml.
  • 及时是经过iOS代码解析处理后,生成的但径直导入进LeanCloud的JSON文件.
    http://ios122.bj.bcebos.com/Post.json
  • 旋即是XML转JSON核心代码,完整代码见文首github链接,XML解析用了一个叔方库Ono:

/* 要实现的逻辑很简单: 
 1.读取XML文件;
 2.解析为JSON,并显示;
 3.将JSON输出为json文件.*/

/* 1.读取并解析XML. */
NSMutableArray * jsonArray = [NSMutableArray arrayWithCapacity: 42];

NSString *XMLFilePath = [[NSBundle mainBundle] pathForResource:@"Post" ofType:@"xml"];
ONOXMLDocument *document = [ONOXMLDocument XMLDocumentWithData:[NSData dataWithContentsOfFile:XMLFilePath] error: NULL];

NSString *XPath = @"//channel/item";

[document enumerateElementsWithXPath:XPath usingBlock:^(ONOXMLElement *element, __unused NSUInteger idx, __unused BOOL *stop) {
    ONOXMLElement * titleElement = [element firstChildWithTag:@"title"];
    ONOXMLElement * descElement = [element firstChildWithTag: @"encoded" inNamespace: @"excerpt"];
    ONOXMLElement * contentElement = [element firstChildWithTag: @"encoded" inNamespace:@"content"];

    NSDictionary * jsonDict = @{
                                @"title": [titleElement stringValue],
                                @"desc": [descElement stringValue],
                                @"body": [contentElement stringValue]};

    [jsonArray addObject: jsonDict];
}];

/* 2.显示JSON字符串. */
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:jsonArray
                                                   options:NSJSONWritingPrettyPrinted
                                                     error:NULL];

NSString * jsonString = [[NSString alloc] initWithData:jsonData
                                             encoding:NSUTF8StringEncoding];

self.textView.text = jsonString;

/*3.存储到文件中.
 真机下,暂无法找到Documents目录下的东西,可以通过模拟器运行此段代码,并通过finder-->前往文件夹,输入此处jsonPath对应的文件路径来获取 Post.json 文件.
 */
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * path=[paths objectAtIndex:0];
NSString * jsonPath=[path stringByAppendingPathComponent:@"Post.json"];

[jsonData writeToFile: jsonPath atomically:YES];
  • 导入后,LeanCloud控制台显示是这样的:

葡京娱乐注册 3

  3.在“Edit with
UliPad”上连续接触右键新建起,项名为“command”,点command,右边出现一个“默认”,后面的数是拖欠的,现在尽管是当此处丰富数据。  

模仿 “花瓣”,重写 LeanCloud Rest Api的iOS REST Client.

连片下去的字,思路及用于很十分程度上参考
@limboy的篇章,但是会相对更加完整.另外,其实 LeanCloud
其实是起和好的iOS
API的,但是是一个虚幻的包裹,和实际利用被动用的纱要API有坏特别不同.两栽方式的距离,有硌类似于是利用
字典等着力项目存储数据,还是采用
自定义的Model来存储数据.个别种植方式,不过大多置评,个人倾向被后同样栽,方便后续之代码重构.

// TODO:Models Group包含了具备与服务端API对应的Model,比如HBPComment

  4.夹击“默认”弹有辑对话框,复制以下字符:

主导组织

利用时,直接引用 YFAPI.h 即可,里面含了所有的Class:

|- YFAPI.h
|- Classes
    |- YFAPIManager.h
    |- YFAPIManager.m
    |- Models
        |- YFPostModel.h
        |- YFPostModel.h
           ...

YFAPIManager包含了具有的跟服务端通信的主意,通过Category来区别:

//
//  YFAPIManager.h
//  iOS122
//
//  Created by 颜风 on 15/10/28.
//  Copyright © 2015年 iOS122. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <AFNetworking.h>

@class RACSignal, YFUserModel;

@interface YFAPIManager : AFHTTPRequestOperationManager

@property (nonatomic, nonatomic) YFUserModel * user; //!< 当前登录的用户,可能为nil.


/**
 *  一个单例.
 *
 *  @return 共享的实例对象.
 */
+ (instancetype) sharedInstance;

@end

/**
 *  私有扩展,其他网路请求的基础.
 */
@interface YFAPIManager (Private)

/**
 *  内部统一使用这个方法来向服务端发送请求
 *
 *  @param method       请求方式.
 *  @param relativePath 相对路径.
 *  @param parameters   参数.
 *  @param resultClass  从服务端获取到JSON数据后,使用哪个Class来将JSON转换为OC的Model.
 *
 *  @return RACSignal 信号对象.
 */
- (RACSignal *)requestWithMethod:(NSString *)method relativePath:(NSString *)relativePath parameters:(NSDictionary *)parameters resultClass:(Class)resultClass;

@end


/**
 *  用户信息相关的操作.
 */
@interface YFAPIManager (User)


/**
 *  用户登录.
 *
 *  获取到用户数据后,会自动更新User属性,所以仅需要在必要的地方观察user属性即可.
 *
 *  @param username 用户名.
 *  @param password 用户密码.
 *
 *  @return RACSingal对象,sendNext的是此类的的单例实例.
 */
- (RACSignal *)signInUsingUsername:(NSString *)username passowrd:(NSString *)password;

/**
 *  登出.
 *
 *  登出,其实就是把 user 属性设为nil.
 *
 *  @return sendNext为此类的单例实例.
 */
- (RACSignal *) logout;

@end

/**
 *  文章相关操作.
 */
@interface YFAPIManager (Post)
//....

@end

Models Group包含了独具与服务端API对应之Model,比如 YFPostModel:

//
//  YFPostModel.h
//  iOS122
//
//  Created by 颜风 on 15/10/28.
//  Copyright © 2015年 iOS122. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <Mantle.h>

/**
 *  文章.
 */
@interface YFPostModel : MTLModel <MTLJSONSerializing>

@property (strong, nonatomic) NSString * postId; //!< 文章唯一标识.
@property (copy, nonatomic) NSString * title; //!< 文章标题.
@property (copy, nonatomic) NSString * desc; //!< 文章简介.
@property (copy, nonatomic) NSString * body; //!< 文章详情.

@end

//
//  YFPostModel.m
//  iOS122
//
//  Created by 颜风 on 15/10/28.
//  Copyright © 2015年 iOS122. All rights reserved.
//

#import "YFPostModel.h"

@implementation YFPostModel

/**
 *  用于指定模型属性与JSON数据字段的对应关系.
 *
 *  @return 模型属性与JSON数据字段的对应关系:以模型属性为键,JSON字段为值.
 */

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    NSDictionary * dictMap = @{
                               @"postId": @"objectId",
                               @"title": @"title",
                               @"desc": @"desc",
                               @"body": @"body"
                               };

    return dictMap;
}

@end

可以类下面的话语,来用JSON转换为Model:

YFPostModel * model = [MTLJSONAdapter modelOfClass:[YFPostModel class] fromJSONDictionary:@{@"title": @"标题", @"desc": @"简介", @"body": @"内容", @"objectId": @"id"} error: NULL];

  ”C:\Program Files\UliPad\UliPad.exe” “%1”

Archive / UnArchive / Copy

各一个Model都设支持Archive / UnArchive /
Copy,也尽管是只要实现和商讨,这半单协议的内容其实就是是指向Object的Property做来处理,所以如果可以当基类里将这些从都统一处理,就会便宜多。考虑到规划之安定和底的可是扩展性,我们下比较知名的老三正值库–Mantle
来处理.你可以使用CocoaPods安装是库房,然后引入头文件 #import <Mantle.h>
到由定义之Model中虽可.

pod 'Mantle' # JSON <==> Model

     即可。

用户的记名和上

预先来说说登录,由于应用RAC,在布局API时,就不需要传入Block了,随之而来的一个题材即使是要在诠释中证sendNext时会发送什么内容.LeanCloud用户登录接口会回来完整的用户信息:

+ (RACSignal *)signInUsingUsername:(NSString *)username passowrd:(NSString *)password
{
    NSDictionary *parameters = @{
                                 @"username": username,
                                 @"password": password,
                                 };

    YFAPIManager *manager = [self sharedInstance];

    // 需要配对使用@weakify 与 @strongify 宏,以防止block内的可能的循环引用问题.
    @weakify(manager);

    return [[[[manager rac_GET:@"login" parameters:parameters]
               // reduceEach的作用是传入多个参数,返回单个参数,是基于`map`的一种实现
               reduceEach:^id(NSDictionary *response, AFHTTPRequestOperation *operation){
                   @strongify(manager);

                   YFUserModel * user = [MTLJSONAdapter modelOfClass:[YFUserModel class] fromJSONDictionary: response error: NULL];

                   manager.user = user;

                   return manager;
               }]
              // 避免side effect,有点类似于 "懒加载".
              replayLazily]
            setNameWithFormat:@"+signInUsingUsername:%@ password:%@", username, password];
}

用户的上出便大概了,直接装user为nil就实施了:

+ (RACSignal *)logout
{
    YFAPIManager * manager = [YFAPIManager sharedInstance];
    @weakify(manager);

    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(manager);

        manager.user = nil;


        [subscriber sendNext: manager];

        [subscriber sendCompleted];

        return nil;
    }];
}

安装过时间和缓存策略

“花瓣”采取的凡重定义 AFHTTPRequestSerializer
子类的不二法门,但事实上用AOP,几行代码就足够了:

// 设置超时和缓存策略.
[self.requestSerializer aspect_hookSelector:@selector(requestWithMethod:
                                                      URLString:
                                                      parameters:
                                                      error:) withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo>info){
    /* 在方法调用后,来获取返回值,然后更改其属性. */
    // __autoreleasing 关键字是必须的,默认的 __strong,会引起后续代码的野指针崩溃.
    __autoreleasing NSMutableURLRequest *  request = nil;

    NSInvocation *invocation = info.originalInvocation;

    [invocation getReturnValue: &request];

    if (nil != request) {
        request.timeoutInterval = 30;
        request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;

        [invocation setReturnValue: &request];
    }
}error: NULL];

行使了一个AOP库,感兴趣的扎这里:
Aspects.

权限验证

其一比较简单些,直接在艺术中添加判断属性self.isAuthenticated 即可:

if (!self.isAuthenticated)
{
  ....
}

其中 isAuthenticated 为基于self.user的演绎属性,其实现如下:

RAC(self, isAuthenticated) = [RACSignal combineLatest:@[RACObserve(self, user)] reduce:^id{
    @strongify(self);

    BOOL isLogin = YES;

    if (nil == self.user || nil == self.user.token) {
        isLogin = NO;
    }

    return [NSNumber numberWithBool: isLogin];
}];

贯彻博客数据的访问.

这边我们若实现访问有具体的博客数据,以证实上述各种基础构件的可用性.为了要示例更有着典型性,我手动将博客数据设为仅指定测试用户(测试用户可以在LeanCloud后台添加和指定)可以看:

要先实现- (RACSignal *)requestWithMethod:(YFAPIManagerMethod)method relativePath:(NSString *)relativePath parameters:(NSDictionary *)parameters resultClass:(Class)resultClass;方法,这是具有网络访问的功底,如下:

/**
 *  内部统一使用这个方法来向服务端发送请求
 *
 *  @param method       请求方式.
 *  @param relativePath 相对路径.
 *  @param parameters   参数.
 *  @param resultClass  从服务端获取到JSON数据后,使用哪个Class来将JSON转换为OC的Model.
 *
 *  @return RACSignal 信号对象.sendNext返回的是转换后的Model.
 */

- (RACSignal *)requestWithMethod:(YFAPIManagerMethod)method relativePath:(NSString *)relativePath parameters:(NSDictionary *)parameters resultClass:(Class)resultClass
{
    RACSignal * signal = nil;

    if (method == YFAPIManagerMethodGet) {
        signal = [self rac_GET:relativePath parameters:parameters];
    }

    if (method == YFAPIManagerMethodPut) {
        signal = [self rac_PUT:relativePath parameters:parameters];
    }

    if (method == YFAPIManagerMethodPost) {
        signal = [self rac_POST:relativePath parameters:parameters];
    }

    if (method == YFAPIManagerMethodPatch) {
        signal = [self rac_PATCH:relativePath parameters:parameters];
    }

    if (method == YFAPIManagerMethodDelete) {
        signal = [self rac_DELETE:relativePath parameters:parameters];
    }

    return [[signal reduceEach:^id(NSDictionary *response){
        id responseModel = [MTLJSONAdapter modelOfClass:resultClass fromJSONDictionary:response error:NULL];

        return responseModel;
    }]replayLazily];
}

然后上加一个用户博客详情访问的章程即可:

/**
 *  获取文章详情.
 *
 *  @param postId 文章id.
 *
 *  @return sendNext为获取到的文章数据模型.
 */

- (RACSignal *)fetchPostDetail:(NSString *)postId
{
    return [[self requestWithMethod:YFAPIManagerMethodGet relativePath:[NSString stringWithFormat:@"classes/Post/%@", postId] parameters:nil resultClass: [YFPostModel class]] setNameWithFormat: @"%@ -fetchPostDetail: %@", self.class, postId];
}

接下来您就算好用接近下面的代码访问博客详情了:

[[[YFAPIManager sharedInstance] fetchPostDetail: @"56308138e4b0feb4c8ba2a34"] subscribeNext:^(YFPostModel * x) {
    NSLog(@"%@", x.body);

    [self.webView loadHTMLString:x.body baseURL:nil];
}];

有些君也许用明白的技术细节

md5 加密

LeanClodu Rest API
需要在地方对masterKey在地面做同破md5加密,我包了一个主意,可以一直用:

/**
 *  将字符串md5加密,并返回加密后的结果.
 *
 *  @param originalStr 原始字符串.
 *  @param lower       是否返回小写形式: YES,返回全小写形式;NO,返回全大写形式.
 *
 *  @return md5 加密后的结果.
 */
- (NSString *) md5Str: (NSString *) originalStr isLower: (BOOL) lower
{
    const char *original = [originalStr UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(original, (CC_LONG)strlen(original), result);
    NSMutableString *hash = [NSMutableString string];
    for (int i = 0; i < 16; i++)
    {
        [hash appendFormat:@"%02X", result[i]];
    }

    NSString * md5Result = [hash lowercaseString];

    if (NO == lower) {
        md5Result = [md5Result uppercaseString];
    }

    return md5Result;
}

动态设置请求头

因为LeanCloud的恳求签权和时空穿有悬挂,所以每次要都要重置部分要求头,此处可以每个请求都手动设置,但是我是应用AOP,直接hook了瞬间(PS:强烈建议不晓AOP为何物的童鞋,学习下,真的蛮爽用起来):

// 每次发送请求前,都需要更新一下 请求头中的 apiClientSecret,因为它是时间戳相关的.
[self aspect_hookSelector:NSSelectorFromString(@"rac_requestPath:parameters:method:") withOptions:AspectPositionBefore usingBlock:^{
    @strongify(self);

    [self.requestSerializer setValue: self.apiClientSecret forHTTPHeaderField: @"X-LC-Sign"];

} error:NULL];

token值葡京娱乐注册自动安装

这其实到头来RAC的基础,让token和user的生成绑定起来就是实行了,如果您想还写user的setter方法,然后起身请求头中token的变化,也是好的(但自我重新喜欢RAC的写照法了):

// 每次用户数据更新时,都需要重新设置下请求头中的token值.
[RACObserve(self, user) subscribeNext:^(YFUserModel * user) {
    @strongify(self);

    [self.requestSerializer setValue:user.token forHTTPHeaderField: @"X-LC-Session"];
}];

“推导属性”的落实

所谓”推导属性”,就是那些附属的,是冲其他性能推断出来的性能,本身应当就中心属性之扭转而自动变化.实现方式发出那么些,可以重复写这属性之getter方法,也足以像下这样:

// 设置isAuthenticated.
RAC(self, isAuthenticated) = [RACSignal combineLatest:@[RACObserve(self, user)] reduce:^id{
    @strongify(self);

    BOOL isLogin = YES;

    if (nil == self.user || nil == self.user.token) {
        isLogin = NO;
    }

    return [NSNumber numberWithBool: isLogin];
}];

总与兆

盖咱们的服务器,是风的PHP服务器,所以本文对LeanCloud的辨析,仅供大家看做技术实现达标之一个参考.具体到祥和的业务细节,可能稍地方,需要特殊处理.关于以上技术讨论的题材,欢迎跟帖讨论!

生一样首主题,会指向单元测试的有些细节做相同细分析.边寻找边学习,总算真到了一个恰如其分的重构我们都出工程的方针了.重构量不略,最核心的少数凡必确保原有的代码不叫影响.也就是说,接下去少两全我若边写单元测试用例,边重构代码.期间遇的有关测试的问题与坑,会立马记录下来,汇总交流.