Using NSPredicate to Find the Object of a Specific Class

NSPredicate is one of powerful classes that helps you a lot when you can use it proficiently. One usage I often use is to use NSPredicate to scan the array for a specific item of a specific class.

1
2
3
4
5
6
NSArray* vcs = self.navigationController.viewControllers;
NSPredicate* classPredicate = [NSPredicate predicateWithFormat:@"class = %@", [TargetViewController class]];
NSArray* filteredArray = [vcs filteredArrayUsingPredicate:classPredicate];
if ([filteredArray count] != 0) {
  ....
}

Adding Pull-to-refresh to Table View

Pull-to-refresh is a common data reloading pattern found in many application. In iOS, there is a UIRefreshControl that we can use easily to add this pull-to-refresh function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)viewDidLoad {

  [super viewDidLoad];

  [self setUpUI];
  [self setUpSearchBar];

  // Set up pull to refresh.
  self.refreshControl = [[UIRefreshControl alloc] init];
  [self.tableView addSubview:self.refreshControl];
  [self.refreshControl addTarget:self action:@selector(refreshControlDidBegin:)
    forControlEvents:UIControlEventValueChanged];
}

- (void)refreshControlDidBegin:(UIRefreshControl* )refreshControl {
  [self syncData];
}

Pitfall of Using String Length as Boolean in Objective-C

As I pointed out in last two posts, I will give one example of how the pitfal of using string length as boolean looks like.

The example is simple, I want to enable the button when the user begins typing in the textview.

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
@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  self.textView1.delegate = self;
  self.textView2.delegate = self;

  self.button1.enabled = NO;
  self.button2.enabled = NO;

  UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard)];
  [self.view addGestureRecognizer:tapGesture];
}


- (void)hideKeyboard {
  if ([self.textView1 isFirstResponder]) {
    [self.textView1 resignFirstResponder];
  }
  else {
    [self.textView2 resignFirstResponder];
  }
}

- (void)textViewDidChange:(UITextView *)textView {
  if ([textView isEqual:self.textView1]) {
    self.button1.enabled = [textView.text length];
  }
  else {
    self.button2.enabled = [textView.text length] > 0;
  }
}

@end

As you see, there are two textviews and two buttons. The first button will be enabled by evaluating
self.button1.enabled = [textView.text length]; and the second will be enabled by evaluating
self.button2.enabled = [textView.text length] > 0; This looks like both should work fine, but no. The first one won’t work as expected and this is the pitfal that some people miss in there code.

Download full example and see the result with your own eyes here.

Implicit Use of String Length in Objective-C as Boolean Value Is Dangerous

In addition to the previous post, I found that implicitly use of string length as boolean is un-reliable.

Try this.

1
2
3
4
5
6
BOOL ugly = [trimmedString length];
BOOL beauty = [trimmedString length] > 0;

BOOL p1 = ugly == beauty;
BOOL p2 = [trimmedString length] == ([trimmedString length] > 0);
BOOL p3 = ((BOOL)[trimmedString length]) == ([trimmedString length] > 0);

If you print out the value of each statement above, you will get

1
2
3
4
5
6
YES
YES

NO
NO
NO

String Length as Boolean Value in Object-C

String length is one of the most common condition that we often face. For me, I like to write it explicitly.

1
self.submitButton.enabled = [trimmedString length] > 0;

However, some people like to make it short and say this is the classic-c style.

1
self.submitButton.enabled = [trimmedString length];

I hate the above code as it is not explicit. We want to determine if the length of the string is more than zero, why don’t we write it that way? In addition, the second statement is harmful. When you do this in Objective-C, the value of the length will be modulo with 256 and the result is used to determine the boolean value. Thus, if the length is 256’s multiplier, the modulus gives 0, which result in a NO Bool value. This is not a grateful result.

Here are useful post of this issue.

君のために - 日之内エミ

title : 君のために-smile remix- (kimi no tame ni -smile remix- )

artist: 日之内エミ

lyrics: 日之内エミ

music : 日之内エミ

source: peffy

romaji: peffy

attakai hi ga sasu yo na sonna nukui nukui kimi no koto ga
sou furereba sugu soko ni wa sotto haru no hareta hi no you na jikan
yumemiteru mitai da konna fuu ni douka samenaide yo itsumademo
zutto sagashiteta yo boku dake no PURINSESU yatto meguriaeta kara chikau yo

sono egao dake no tame ni sono egao mamoru tame ni
boku nari ni dekiru koto ga aru kara
sono egao o miru tame ni sono egao dake no tame ni
boku no subete o nagedaseru kara

mada shiranai bubun o motto shiritsukushitai n’da yo sou
atarashii kimi sagashi shite mata mitsukeru yo kyou mo hitotsu
kuchi ni wa shinai kedo itsukaraka kono saki no koto to ka kangaete
zutto ite hoshii na boku dake no PURINSESU ima no kono kanji no mama itai yo

kimi no egao dake no tame ni kimi no egao mamoru tame ni
sasaerareru koto ga aru naraba
kimi no egao o miru tame ni kimi no egao dake no tame ni
boku wa tsuyoku nareru n’da yo

sono egao dake no tame ni sono egao mamoru tame ni
boku nari ni dekiru koto ga aru kara
sono egao o miru tame ni sono egao dake no tame ni
boku wa subete o nagedaseru yo
boku wa tsuyoku nareru n’da yo

KANJI:

あったかい陽が差すよな そんなぬくいぬくい君のことが
そう 触れればすぐそこには そっと春の晴れた日の様な時間
夢見てるみたいだ こんな風に どうか覚めないでよ いつまでも
ずっと探してたよ 僕だけのプリンセス やっと巡り会えたから誓うよ

その笑顔だけの為に その笑顔守るために
僕なりにできることがあるから
その笑顔を見る為に その笑顔だけの為に
僕のすべてを投げ出せるから

まだ知らない部分をもっと 知り尽くしたいんだよ そう
新しい君探しして また見つけるよ今日も 一つ
口にはしないけど いつからか この先のこととか 考えて
ずっといて欲しいな 僕だけのプリンセス 今のこの感じのまま いたいよ

君の笑顔だけの為に 君の笑顔守る為に
支えられることがあるならば
君の笑顔を見る為に 君の笑顔だけの為に
僕は強くなれるんだよ

その笑顔だけの為に その笑顔守るために
僕なりにできることがあるから
その笑顔を見る為に その笑顔だけの為に
僕はすべてを投げ出せるよ
僕は強くなれるんだよ

http://hiphopvomit.blogspot.com/

Uploading File to Amazon S3 Using Plupload on Rails

PLUpload is a great freee javascript library that let’s you upload the file to the server, either it’s a real server or a storage cloud service like Amazon S3. It provides various upload interface through its runtimes (a frontend interface unit that handle file uploading). There are 6 runtimes available which are HTML4, HTML5, Flash, Silverlight, Gears and Browserplus. Each runtime has different characteristic. For example, Flash runtime lets you select the file from file explorer dialog, while HTML5 runtime also support drag-and-drop.

Plupload is used in one the projects I’m working with. At first, we use Plupload to upload the file to Heroku. However, there are needs from the client for large file upload support. This is quite a problem with Heroku as it requires the request to be finished within 30 second. This old upload is supported by Paperclip. When the user uses PLUpload to upload the file, it goes to Heroku, then Paperclip handles the post-processing task and uploads the file further to Amazon S3. If the users had to upload the large file, that file can not be passed to Heroku due to its time-out critiria. Thus, it will not be uploaded to S3 too. We need to change the behavior of this procedure.

The solution we can figure out is to use Plupload to upload the file directly to S3, then let’s Paperclip do post-processing as background job (This will be written in the next coming post). One thing to remind is that, currently, S3 does not support file uploading via HTML5. As a result, we need to select other runtimes. The best choice in my opinion is Flash even if it seemed outdate. The following code shows how the configuration is done.

index.html.erb
1
2
3
4
5
<div class="upload_container" id="media-upload">
  <span id="browse-prompt">Click here to upload new file</span> <span class="button altbutton" id="browser">browse</span> </div>
  <div id="progress" style="display:none"></div>
  <div id="uploading-item" style="display:none;"></div>
</div>
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
<code language="javascript">
$(document).ready(function(){
  uploader = new plupload.Uploader({
    runtimes: 'flash,silverlight',
    container: 'media-upload',
    browse_button: 'browser',
    max_file_size: '200mb',
    flash_swf_url: '/javascripts/lib/plupload/plupload.flash.swf',
    silverlight_xap_url: '/javascripts/lib/plupload/plupload.silverlight.xap',
    url: gon.temporaryFileLocation,
    multipart: true,
    multipart_params:{
      'key': 'your/folder/${filename}', // for example 'media/tmp/${filename}'
      'Filename': '${filename}',
      'acl': gon.acl,
      'Content-Type': 'binary/octet-stream',
      'success_action_status': '201',
      'AWSAccessKeyId' : gon.accessKeyId,
      'policy': gon.policy,
      'signature': gon.signature
    },
    file_data_name: 'file',
    filters: [
      {title: "Image files", extensions: "jpg,jpeg,gif,png"},
      {title: "Video clips", extensions: "mov,mpg"},
      {title: "Executable files", extensions: "exe"},
      {title: "Compressed files", extensions: "rar,zip"},
      {title: "Document files", extensions: "pdf,ppt,pptx,doc,docx,xls,xlsx"}
    ]
  });

  uploader.init();

  uploader.bind('Error', function(up, args) {
    up.refresh();
  });

  uploader.bind('FileUploaded', function(up, file, response) {
    notice_uploaded_file(file.name);
    $("#uploading-item").fadeOut("fast");
    if (up.total.uploaded == up.files.length){
        finished_all_file = true;
    }
  });

  uploader.bind('FilesAdded', function(up, files) {
    uploader.start();
    $('#progress').progressbar();
    $('#progress').show();
    $('#progress').progressbar('value', 10);
    up.refresh();
  });

  uploader.bind('BeforeUpload', function(up, file){
    file_word = function(i){ if(i==1){return " file ";}return " files ";};
    file_upload_log = up.total.uploaded +  file_word(up.total.uploaded) +
                      "uploaded from "+ up.files.length + file_word(up.files.length) + "total";
    $("#uploading-item").html("Uploading "+
      file.name + "<br/>(<span id='progress_text'>0%</span>, "+
      file_upload_log + ")"
    );
    $("#uploading-item").fadeIn("slow");
  });

  uploader.bind('UploadProgress', function(up, file) {
    $('#progress').progressbar('value', file.percent);
    $("#progress_text").html("current progress " + file.percent + "%");
    up.refresh();
  });
});
</code>

<b>And Rails controller</b>
<code language="ruby">
def index
  access_key_id     = "your access key id"
  secret_access_key = "your secret access key"
  acl               = "your acl"
  max_file_size     = "100"
  expired_date      ||= 10.hours.from_now.utc.iso8601

  s3_bucket = "your bucket"
  gon.temporary_file_location = "http://s3.amazonaws.com/#{AppConfig[:s3_bucket]}/"
  gon.acl = acl
  gon.access_key_id = access_key_id
  gon.policy = Base64.encode64(
    "{'expiration': '#{expired_date}',
      'conditions': [
        {'bucket': '#{s3_bucket}'},
        {'acl': '#{acl}'},
        {'success_action_status': '201'},
        ['content-length-range', 0, #{max_file_size}],
        ['starts-with', '$key', ''],
        ['starts-with', '$Content-Type', ''], 
        ['starts-with', '$name', ''],
        ['starts-with', '$Filename', '']
      ]
    }").gsub(/\n|\r/, '')

  gon.signature = Base64.encode64(
    OpenSSL::HMAC.digest(
      OpenSSL::Digest::Digest.new('sha1'),
      secret_access_key, gon.policy
    )
  ).gsub("\n","")
end

Note: I use Gon to parse variable from Rails controller to Javascript.

Android Studio With Offline Gradle

By default, when you use android studio with Gradle, it will downloadd dependencies every times you build the code. To turn this off, we have to enable offline mode. To do this, go to preference, select gradle, then check ‘offline work’ in the global gradle setting section.

Hello Octopress

This is a newly post!.

1
[rectangle setX: 10 y: 10 width: 20 height: 20];
Discover if a number is prime
1
2
3
4
5
class Fixnum
  def prime?
    ('1' * self) !~ /^1?$|^(11+?)\1+$/
  end
end