Comments

Make-macOS-App-With-Sunus-Part-1-Create-Window

和 Sunus 一起开发 macOS App - 创建一个 Window

有「和 Sunsu 一起开发 macOS App」这一系列 Blog 的想法已经有一阵子了, 希望能坚持下来:)

创建 Window

创建 Window 是一个 macOS App 非常基础的一个部分, 在 macOS 的开发当中, Window 的使用范围比 iOS 要大得多也更加灵活, 所以我选择该系列的第一章就由创建 Window开始.

默认的 Window

打开 Xcode , 新建项目的项目, 会有一个默认的 Window 提供, 我之前都没怎么注意, 是这样的

Default_Window

这个 Window 初看起来也还好, 但是有时候我们会有一些希望能够自定义的地方. 这是 Xcode 的 GUI 界面就显得有些不够用了. 我们接下来会详细的研究如何通过代码来自定义我们的 Window.

Window 的基础知识

在 macOS 当中, 窗口一共由几个部分组成

  1. TitleBar
  2. ToolBar
  3. 主体区域

默认情况下,这三个区域, 如图显示是这样(黑色边框的部分是 Toolbar)

Window_Layout

  • 要显示 Toolbar 需要实现 NSToolbarDelegate 里的几个方法

开始用代码定制一个 Window

我们希望实现一个这样的 Window

Window_Demo

看着还不错😋

实现一个这样的 Window, 初步看来, 需要几个地方稍加改动:

  1. TitleBar 透明处理
  2. TitleBar 的 Title 隐藏
  3. Toolbar 不显示
  4. 设置背景图片
  5. 实现无边框的 TextField

其实看来 应该也就是 1~3 需要弄下, 4比较简单. 5不在本文的讨论范围内. 那么, 开始吧. 在详细一点, 我们需要做的就是设置 Titlebar , ToolBar, 以及 Window 的一些通用属性(背景等) 并且 Window 的一些属性, 虽然看起来像是属于 TitleBar 的, 其实是通过 NSWindow 的styleMask 进行修改的, 在之后相关的地方也会一并说明.

TitleBar

为什么要 TitleBar

关于 TitleBar 可能会问, 「看着最终效果, 好似不需要 Titlebar 吖?」

其实, Titlebar 做的不只是显示自己这个事情, 只要使用了 TitleBar, 他还让 Window 附带了:

  1. 圆角边框 + 阴影效果
  2. 能够支持鼠标在 TitleBar 区域的拖拽移动位置的效果

  3. 如果实在不想用 Titlebar, 那么你需要自己实现一个 圆角的边框(如果需要) , 边框阴影效果(如果需要) , 支持拖拽(如果需要) , 还是比较麻烦的.

所以, 使用 Titlebar 还是能够得到很多附加的便利的:)

深入 Titlebar

关于 TitleBar , 有几个属性/方法值得留意:

1
2
3
@property (copy) NSString *title;
@property BOOL titlebarAppearsTransparent;
@property NSWindowTitleVisibility titleVisibility;

其中 titlebarAppearsTransparent 这个属性很好理解, 设置成 YES 即可, 即让 Titlebar 透明.

然后, titleVisibility 这个属性也比较好理解,就是是否显示 WindowTitle(其实就是Title 所在的那个 TextField) 有两个可能值 NSWindowTitleVisibleNSWindowTitleHidden

Toolbar

Toolbar 就没啥好说的, 默认是没有的.

如果需要创建的话 需要实现 NSToolbarDelegate 里的几个方法

设置背景图片

  1. 通过修改 NSWindow 的 backgroundColor 属性即可
1
self.backgroundColor = [NSColorcolorWithPatternImage:backgroundImage];
  1. 这个时候, 你会发现 titlebar 的那一块会是比较突兀的灰色, 所以, 也需要把 titlebar 的 titlebarAppearsTransparent 属性设置为 YES , 即将 titlebar 设置为透明即可.

Textfield 和其他

实现一个无边框的 Textfield 暂时就不在本文的范围内了, 可以通过代码来查看:)

END

就这样, 一个还算好看的 Window 就开发好了, 我们可以继续接下来的开发了:)

Feedback

关于本文任何问题可以留言:)

Comments

AFNetworking 2.0 是如何发送网络请求的?

原始方法

我们在开发 iOS , Mac App 的过程当中一定有接触过发送网络请求, 最初我们有使用的是这样的:

  1. 创建一个类, 然后使用 NSURLConnectionDelegate

  2. 初始化 并发送 请求, 类似这样

1
2
3
4
5
6
7
8
9
10
11
12
13

NSURL *httpsURL = [NSURL URLWithString:@"http://sunus.me";

// prepare parameters
NSString *postString = [NSString stringWithFormat:@"param1=%@¶m2=%@", @"para1", @"para2"];
NSData *postData = [postString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:httpsURL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60.0f];
[request setHTTPMethod:@"POST"];
[request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[postData length]] forHTTPHeaderField:@"Content-Length"];
[request setHTTPBody:postData];

// send the request
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
  1. 然后在这几个 Delegate 方法里添加对于的处理返回值的逻辑.(实现略)
1
2
3
4
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;

使用 Block.

在 Objective-C 有了 Block 之后, 有很多的网络框架都支持了 Block 的接口. 一般方法声明为这样:

1
2
3
4
5
typedef void(^success)(id response);
typedef void(^failure)(NSError *error);

-(void)makeSomeRequest:(success)successBlock
                  fail:(failure)failBlock;

然后这样使用

1
2
3
4
5
6
7
[httpClient makeSomeRequest:^(id response) {
    // do stuff with response
    NSLog(@"%@", response);
} fail:^(NSError *error) {
    // handle the error
    NSLog(@"%@", error);
}];

这类方法的实现也比较简单, 主要就是在 makeSomeRequest 里, 把两个回调用 copy 住. 然后在原始方法的Delegate 当中, 比如 - (void)connection:(NSURLConnection )connection didReceiveData:(NSData )data 以及 - (void)connection:(NSURLConnection )connection didFailWithError:(NSError )error 当中再调用对应的 block 方法即可.

使用AFNetworking

AFNetworking 则是做了更多的封装, 这也是我们需要重点研究的, AFNetworking 到底 是如何将一个 请求发送出去的 ?

本文是以 AFNetworking 2.5.4 为例子, 调用一个 HTTP GET 请求的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[[AFAppDotNetAPIClient sharedClient] GET:@"stream/0/posts/stream/global" parameters:nil success:^(__unused AFHTTPRequestOperation *operation, id responseObject) {
           NSArray *postsFromResponse = [responseObject valueForKeyPath:@"data"];
        NSMutableArray *mutablePosts = [NSMutableArray arrayWithCapacity:[postsFromResponse count]];
        for (NSDictionary *attributes in postsFromResponse) {
            Post *post = [[Post alloc] initWithAttributes:attributes];
            [mutablePosts addObject:post];
        }

        if (block) {
            block([NSArray arrayWithArray:mutablePosts], nil);
        }
    } failure:^(__unused AFHTTPRequestOperation *operation, NSError *error) {
        if (block) {
            block([NSArray array], error);
        }
    }];

AFAppDotNetAPIClient 的实现如下, 可以看到, 他的基类是 AFHTTPRequestOperationManager

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

#import <Foundation/Foundation.h>
#import "AFHTTPRequestOperationManager.h"

@interface AFAppDotNetAPIClient : AFHTTPRequestOperationManager

+ (instancetype)sharedClient;

@end

static NSString * const AFAppDotNetAPIBaseURLString = @"https://api.app.net/";

@implementation AFAppDotNetAPIClient

+ (instancetype)sharedClient {
    static AFAppDotNetAPIClient *_sharedClient = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedClient = [[AFAppDotNetAPIClient alloc] initWithBaseURL:[NSURL URLWithString:AFAppDotNetAPIBaseURLString]];
        _sharedClient.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
    });
    
    return _sharedClient;
}

@end

跟着我左手右手一个慢动作..

  1. 我们先看看 [AFAppDotNetAPIClient GET] 方法干了什么事情, 该方法直接调用的是基类的 GET 方法.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// AFNetworking Source Code
// AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m:137

- (AFHTTPRequestOperation *)GET:(NSString *)URLString
                     parameters:(id)parameters
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];

    [self.operationQueue addOperation:operation];

    return operation;
}

很简单, 就是创建一个 AFHTTPRequestOperation , 然后放到 operationQueue , 然后返回这个 operation. 目前来看 , 返回的 operation 暂时对我们来说是没有用的, 那我们就要重点研究, 创建 operation 的过程中发生看什么事, 以及 这个 operationQueue 到底是什么鬼.

  1. 先看
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
// AFNetworking Source Code
// AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m:94

- (AFHTTPRequestOperation *)HTTPRequestOperationWithHTTPMethod:(NSString *)method
                                                     URLString:(NSString *)URLString
                                                    parameters:(id)parameters
                                                       success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                                                       failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
#pragma clang diagnostic pop
        }

        return nil;
    }

    return [self HTTPRequestOperationWithRequest:request success:success failure:failure];
}

在这里, 暂时先把 requestSerializer 忽略, 看 HTTPRequestOperationWithReques

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// AFNetworking Source Code
// AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m:118

- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
                                                    success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                                                    failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    operation.responseSerializer = self.responseSerializer;
    operation.shouldUseCredentialStorage = self.shouldUseCredentialStorage;
    operation.credential = self.credential;
    operation.securityPolicy = self.securityPolicy;

    [operation setCompletionBlockWithSuccess:success failure:failure];
    operation.completionQueue = self.completionQueue;
    operation.completionGroup = self.completionGroup;

    return operation;
}

在这里, 我看到了一开始的 operation 是在这里得到初始化的. 接下来, 那个 setCompletionBlockWithSuccess 看起来就是把 success , failure 这两个 block 给 hold 住的地方. 但是, 仅仅做了这些事情吗? 继续看.

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
// AFNetworking Source Code
// AFNetworking/AFNetworking/AFHTTPRequestOperation.m:107
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
    self.completionBlock = ^{
        if (self.completionGroup) {
            dispatch_group_enter(self.completionGroup);
        }

        dispatch_async(http_request_operation_processing_queue(), ^{
            if (self.error) {
                if (failure) {
                    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                        failure(self, self.error);
                    });
                }
            } else {
                id responseObject = self.responseObject;
                if (self.error) {
                    if (failure) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            failure(self, self.error);
                        });
                    }
                } else {
                    if (success) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            success(self, responseObject);
                        });
                    }
                }
            }

            if (self.completionGroup) {
                dispatch_group_leave(self.completionGroup);
            }
        });
    };
#pragma clang diagnostic pop
}

在这里, 主要是请求的成功 / 失败 两种结果, 通过 dispatch_async 放到了 http_request_operation_processing_queue() 这个队列当中执行, 暂时不用太纠结这个队列, 就当成是一个队列就好了. 成功执行 success(self, responseObject) , 失败 执行 failure(self, self.error);

我们还要注意一点, 这里其实还没到头,

1
2
3
self.completionBlock = ^{
    ...
};

这里, 其实还有调用了 setCompletionBlock 方法, 如下

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
// AFNetworking Source Code
// AFNetworking/AFNetworking/AFURLConnectionOperation.m:400
- (void)setCompletionBlock:(void (^)(void))block {
    [self.lock lock];
    if (!block) {
        [super setCompletionBlock:nil];
    } else {
        __weak __typeof(self)weakSelf = self;
        [super setCompletionBlock:^ {
            __strong __typeof(weakSelf)strongSelf = weakSelf;

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
            dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop

            dispatch_group_async(group, queue, ^{
                block();
            });

            dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
                [strongSelf setCompletionBlock:nil];
            });
        }];
    }
    [self.lock unlock];
}

这里, 应该是最开始1中的

1
 AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];

结束的地方.

但是, 我们感觉好似还有好多事情没搞清楚.. 比如, 这个请求, 到底是, 什么时候, 被发出去的? 如果我们有抓包的话, 可以看到执行完这行代码之后, 其实请求还没发送出去.

接下来, 我们看1中还有哪些地方可以研究.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// AFNetworking Source Code
// AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m:137

- (AFHTTPRequestOperation *)GET:(NSString *)URLString
                     parameters:(id)parameters
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];

    [self.operationQueue addOperation:operation];

    return operation;
}

对了, 就是这个. [self.operationQueue addOperation:operation]; 如果我们知道什么是 NSOperation 以及什么是 NSOperationQueue 的话, 那么, 问题就明朗很多. 简单来说.

每个 NSOperation 都会有几个方法 , __start__ , __exectuing__ , __finish__ , __cancel__ 等几种状态, 当把一个 NSOperation 添加到 NSOperationQueue 时, 会自动调用 NSOperation 的 __start__ 方法.

看到这里

AFNetworking/NSURLConnection/AFURLConnectionOperation.m

里, 那些熟悉的 Delegate 又回来了:) 看看那些方法, 就知道请求是从这儿发出去的:)

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
//AFNetworking/NSURLConnection/AFURLConnectionOperation.m:443

- (void)start {
    [self.lock lock];
    if ([self isCancelled]) {
        [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    } else if ([self isReady]) {
        self.state = AFOperationExecutingState;

        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
    }
    [self.lock unlock];
}

- (void)operationDidStart {
    [self.lock lock];
    if (![self isCancelled]) {
        self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        for (NSString *runLoopMode in self.runLoopModes) {
            [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
            [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
        }

        [self.outputStream open];
        [self.connection start];
    }
    [self.lock unlock];

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
    });
}

- (void)finish {
    [self.lock lock];
    self.state = AFOperationFinishedState;
    [self.lock unlock];

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
    });
}

最后, 当 finish 之后, 会调用最初的 completionBlock. 就完成了一次请求的收发.

Happy coding!

Comments

Summary for 2014 & Resolutions for 2015

Hello and Happy new year to you all:)

I was so busy those days and I am back to writing posts in the early beginning of 2015.

In fact, I’ve been planning to write this post weeks ago as I always did, but you did, I just too busy to write posts, right now, I also need to set up my server, God knows what will happen.

Now, Let’s begin.

Summary for 2014

  • This is the biggest one and one really changed me a lot, that is, I finally found someone, I gave her a very sweet nickname ‘xjx’. She was just a normal girl to me when we first meet, as the day went by, i started to realized that how special & cute she is, she started to mad at me sometimes as well:) She takes care of me very well and we love each other. Oh God! she is such a cute girl and i just can’t stop saying that:)Every time she smiles i could felt the simply fact through her eyes, that is, we are happy together:) Till now, our feelings to each other doesn’t seems to fade. Being with her, i feel more confident, happy, and sweet. And most importantly, I want to give her more joys, just like she gave me^

  • This is truly a great year for me. I graduated from university and started to work. I really love my job right now, I love programming, I write codes almost everyday, even in weekends, but I never felt boring about it. Also, this job pays me well so that I could buy stuffs for me and xjx. I never thought about i will be a Mac or iOS programming this year, but you know what, i not only write Mac programmings, but also make iOS Apps. And I really did those things well very, I just cannot image how good I will be in the end of 2015.

  • Let’s talk about my work a little bit, it’s really busy and sometimes I felt pressure, but i think I can handle those stuffs, just because i think I can. It’s a whole new experience working with different people, but it’s interesting.

  • I know my mom, my family and xjx are really proud of me, I felt truly happy for that:)

Resolutions for 2015

  • Be a good guy, good son.

  • Be a good boyfriend, do not let xjx down, for she gave me her best year of her life. We’ll have more fun this year!

  • Helping xix to find some that really interests her.

  • Even though this year I will have more work & pressure to deal with, that’s for sure. Nonetheless, never, never let those stuffs take me down. I don’t want to be a work-machine. I still need to keep improving myself, learning new skills, exploring new things and finding more interesting stuffs in our life. Just like I did all the time.

  • Be a good iOS & Mac developer.

  • If possible, making a real App, it’s talking about for years.

  • I wish my family and xjx a healthy and happy year.

  • It’s strange. I cannot think much of it right now.

Comments

Thoughts After Training

Hi, I am just back from an almost two-weekends non-stop training class held by my company. It’s a lot of fun and I met a lot of some amazing guys. We might be very good friends in the future.

But in this post, neither those brain-wash stuffs nor so called company culture will be talked about.

The main point of me writing this post is that I found some attitudes in some people and I like to talk about.

So, let’s begin, there’s some background. We got a task to make a simple web app within about two or three days, and after some discussion, i was voted to be the one that takes control, consequently, I design The whole architecture and assign the tasks to my teammates

So, after we started carrying out the project, here are some attitudes I saw in the team and my thoughts towards them (No bad feelings.)

  • Some people know how to their jobs. And they did contribute. I did appreciate it, they are motivated.
  • Some people are less motivated. In fact, they are very skilled. But, they do not want to contribute more, just finished his work that assigned to him then leave
  • Also, there are two kinds of people that might not been fit for a particular task:
    • One will ask other people what he can do or what he needs to learn in order to finish some task.
    • While the other one will just stay quiet and do nothing.

Obviously, to me, as the guy in control, it’s easy to figure out that what kinds of attitude are better. So, I write this post to remind me what attitudes I should have in the future, if I am in some similar situation in the future

Comments

Caught a Break to Write Something

Hi, yeah, finally I caught a break to write something to share with you guys. It’s been an amazing times here in Hangzhou, it’s too busy to write, but I couldn’t wait to share with you.

Hmm, but right now, I do not even know where to start, so, just keep reading.

Let’s talk about my work first, going to work and getting paid is one of my biggest change happened to me lately, I sometimes don’t even realised that i am no longer a student anymore:)

I’ve been assigned to a new team that I found that it’s much more interesting and challenging than the previous one, consequently, I am feeling more motivated. It’s quite a new field for me, but I am getting better at it. I get the feeling that the product I am making right now, could be something that I will be proud of.

Besides of my work, i am also doing well with my love life. She loves me and cares for me. I just had my very first Valentine’s day with her last week, that was just awesome! I flew to Kunming, a city near her hometown. Then we had some famous food of Yunnan. Another main event is that we’ve gone to a famous lake with a great hotel. Such a day!

So, I am having a really good time here in Hangzhou and I wish to have some more to share with you.

Comments

Last Days of Being a Student

Hi, it’s been a while since the last post. Now I am almost half way out of this school. After the final thesis defense take place in the early June, I will officially walk out this school, a place that brought me so much joy, sadness and brotherhood.

I hurry back to Tianjin in the early May, and I amazingly finished the final project and it’s paper within a week. And it seems like a great work that I’ve made. I’ve never wrote this amount of code or word within such a short notice. But anyway, I made it, so that I can have time to have fun:) I will go back to Hangzhou tomorrow and stay for a few days, to be with that girl I met months ago then fell in love with. The feeling that having someone care for you is great. Also, I accomplished the most import goal of this year:)

She is great, from as far as i can tell:)

So now, I consider my university life is completed .

I thank you all!

Comments

Sunus Met Someone

Last Saturday, April 19th, 2014, I met someone, she is a beautiful and interesting girl.

We had a lot of fun, that’s all i can tell right now and i think there will be MORE to come.

Good night:)

Comments

0x18 & Getting Ready

Hi, I am writing this in my original kind-of-awesome apartment in Hangzhou, a city where I could live for a while.

I got there a week ago and I celebrate my 0x18th birthday with a friend I made in Hangzhou. She even brought me a birthday cake, which she insisted to do so.

On my birthday, I went to Xixi National Park, it has a great landscape with trees, flowers and lakes. The air is excellent as well, not like downtown in Hangzhou. The funny part was, when I ready to get out of the park, I decide to walk, because I thought I could do this but, in the end I almost got lost and my phone is dying, luckily I saw a shuttle. Otherwise, you might not be able to see this post:)

xixi1 xixi2 xixi3 xixi4 xixi5 bd

Another thing is I rented an awesome apartment. It’s so great and it even got a digital panel in the room, it can control all the electrical devices in the room, it’s really amazing! And I did a lot of housework as well, because I will live in this apartment for some time, I don’t want it to be a mass.

And the last thing is, I will sign up for Alibaba tomorrow, finally, wow. I don’t know what my days will be, but I think it will be so much funny & Exciting! Let’s wait and see.

Comments

Feeling Young & Energetic Again

Good morning to you all:)

I’ve been back to university for some days, and i just had a really great fun in Happy-Valley in Tianjin with my new friend:)

I’m always enthusiasm about for stuffs like Happy-Valley since I was a kid. When I started my university here, I’ve been to Beijing’s Happy-Valley for some times. That was fun! Now, I finally had a chance to go to Tianjin’s Happy-Valley, which I dreaming for some time:) I really mean it, so thank you, my friend came with me to this wonderful & exciting place.

So, we had a great hot-pot in one of my favorite restaurants then went to the hotel the other night. That hotel is great with a giant lobby.

Thanks to me to pick this hotel which is only a few steps away from the Happy-Valley.

Then, the adventure began. We almost played all the stuffs except those that are suspended due to some maintaining reasons.

The roller coasters, haunted houses, etc.. That were so exciting which I haven’t experienced for some years and now, I am feeling that again, just like a teenager:) Finally, I got wetted.

I am just feeling I am still younger and energetic:) and thank you, my new friends for spending your time with me. That’s a fantastic experience.

PS, I found a cool stuff call 「Instax 」, it’s a kind of cameras that can produce the actual photos instantly. No wonder so many gift tips for girls recommend it. it’s just interesting and looks cute! i’d love to buy one some time:)

wet

Comments

Having Fun

Hi, I am having a really really awesome vacation now and I met some really really attractive girls that i wished we could met earlier! That’s why I am not coding as much as i used to.

Basically, i met a girl that almost fit every criteria in my “LIST” for what kind of girl i wanna be with.

  • She looks nice and attractive, especial her eyes.
  • She is a fan of Taylor Swift, She once taught me to sing Taylor’s songs, but my voice ruined everything:)
  • She majored in Math & economics, which some sort of means that she is not dumb:) and now she is a Math teacher.
  • She loves to eat delicious foods.
  • We share some common interests, it’s really rare in this city.
  • We sometime chat for hours in the late night and say goodbyes.
  • She has plans for her future.
  • I’d been in her bedroom for like one or two minutes^
  • blah..blah

I feel really really sad for the fact that we’re working & living in two different cities and there’s not much time left for us:(

We don’t know much about each other yet, but I think she might found me interesting as well, sometimes when we hang out i could felt that she cared for me on purpose, just like someone I used to be with, then I pretended like i don’t know. LOL. but I once try to set her up with my best friend which pissed her off, now my friend is kinda fall in love with her, that’s really funny! I don’t know how i felt when i saw two of them flirting in front of me. anyway, since i am not able to stay in this city, there’s no chance for us to do this long distance thing:( that’s life, hum?

So, I start to hoping my life in Hangzhou could be wonderful.

that’s it, good night:)