MAZYOD’S
DEVDIARY

Blabbering on, and on, and on…

What the Snippet

I am really getting used to this video blogging business. It feels like I want to make all future posts videos. So easy, so convenient…

This one is about using Xcode snippets to speed up your development. I present a use case with cocos2d-x, but it can be used with anything really… Even Swift ;).

Here are the snippets. Just drag the code over to the snippets area in Xcode:

1
2
3
4
5
6
7
8
9
class <#class#> : public <#superclass#>
{

public:

    static <#class#> *create(<#args-definition#>);
    virtual bool init(<#args-definition#>);

};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<#class#> *<#class#>::create(<#args-definition#>)
{
    <#class#> *obj = new <#class#>();
    obj->init(<#args#>);
    obj->autorelease();

    return obj;
}

bool <#class#>::init(<#args-definition#>)
{
    if (!<#superclass#>::init(<#superargs#>))
    {
        return false;
    }

    return true;
}

Regex Fun

Today, I went on a regex mission to refactor our code base, and ended up replacing a huge lot of code with macros, which saved us around 450 lines of code throughout the project. Now, we can use those macros to work faster, too!

Here are all the commands I wrote, good luck figuring anything out :p

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep NSNotificationCenter\s+
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep NSNotificationCenter\\s+
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NSNotificationCenter\\s+"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)\\s+selector"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)\\s+selector\\((\\w+)\\)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)\\s+@selector\\((\\w+)\\)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)\\s+\@selector\\((\\w+)\\)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)\\s+\\@selector\\((\\w+)\\)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)\\s+selector:@selector\\((\\w+)\\)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:(\\w+)\\s+selector:@selector\\((\\w+)\\)\\s+name:(\\w+)\\s+object:(\\w+)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ blog_new_post regex-disaster
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:(.*?)\\]"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*(.*?)\\]"
[[NSNotificationCenter defaultCenter] addObserver:tar selector:@selector(sel) name:nam object:nil]
[[NSNotificationCenter defaultCenter] addObserver:tar selector:sel name:nam object:nil]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*(.*?)\\s*\\]"
[[NSNotificationCenter defaultCenter] addObserver:tar selector:@selector(sel) name:nam object:nil]
[[NSNotificationCenter defaultCenter] addObserver:tar selector:sel name:nam object:nil]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*nil\\s*\\]"
[[NSNotificationCenter defaultCenter] addObserver:tar selector:@selector(sel) name:nam object:nil]
[[NSNotificationCenter defaultCenter] addObserver:tar selector:sel name:nam object:nil]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*nil\\s*\\]"
[[NSNotificationCenter defaultCenter] addObserver:tar selector:@selector(sel) name:nam object:nil]
[[NSNotificationCenter defaultCenter] addObserver:tar selector:sel name:nam object:nil]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*nil\\s*\\]" "NC_ADD\\(\\g<1>, \\g<2>, \\g<3>\\)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*nil\\s*\\]" "NC_ADD\\(\\g<1>, \\g<2>, \\g<3>\\)" ""
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*nil\\s*\\]" "NC_ADD\\(\\g<1>, \\g<2>, \\g<3>\\)" 0
[[NSNotificationCenter defaultCenter] addObserver:tar selector:@selector(sel) name:nam object:nil]
[[NSNotificationCenter defaultCenter] addObserver:tar selector:sel name:nam object:nil]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*nil\\s*\\]" "NC_ADD\(\\g<1>, \\g<2>, \\g<3>\)" 0
[[NSNotificationCenter defaultCenter] addObserver:tar selector:@selector(sel) name:nam object:nil]
[[NSNotificationCenter defaultCenter] addObserver:tar selector:sel name:nam object:nil]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*nil\\s*\\]" "NC_ADD(\\g<1>, \\g<2>, \\g<3>)" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NC_ADD\\(.*?\\)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NC_ADD\\(.*?\\);"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NC_ADD\\(.*?\\);\\s+NC_ADD"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "(NC_ADD\\(.*?\\);)(\\s*?\n)+(\\s*NC_ADD)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "(NC_ADD\\(.*?\\);)(\\s*?\n)+(\\s*NC_ADD)" "\\g<1>\n\\g<3>"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ y
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "(NC_ADD\\(.*?\\);)(\\s*?\n)+(\\s*NC_ADD)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "(NC_ADD\\(.*?\\);)(\\s*?\n){2,}(\\s*NC_ADD)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_g "(NC_ADD\\(.*?\\);)(\\s*?\n){2,}(\\s*NC_ADD)"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "(NC_ADD\\(.*?\\);)(\\s*?\n){2,}(\\s*NC_ADD)" "\\g<1>\n\\g<3>"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[NSNotificationCenter"
[[NSNotificationCenter defaultCenter] addObserver:tar selector:sel name:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotification:notif]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotification:notif]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[[NSNotificationCenter defaultCenter] removeObserver:tar]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s+addObserver:\\s*(.*?)\\s+selector\\s*:\\s*@selector\\s*\\((.*?)\\)\\s+name:(.*?)\\s+object:\\s*(.*?)\\s*\\]" "NC_ADDO(\\g<1>, \\g<2>, \\g<3>, \\g<4>)" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "(NC_ADD\\(.*?\\);)(\\s*?\n){2,}(\\s*NC_ADD)" "\\g<1>\n\\g<3>"
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "(NC_ADD\\(.*?\\);)(\\s*?\n){2,}(\\s*NC_ADD)" "\\g<1>\n\\g<3>" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "(NC_ADDO?\\(.*?\\);)(\\s*?\n){2,}(\\s*NC_ADD)" "\\g<1>\n\\g<3>" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "(NC_ADDO?\\(.*?\\);)(\\s*?\n){2,}(\\s*NC_ADD)" "\\g<1>\n\\g<3>" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotification\\s*:\\s*(.*?)\\s*(.*?)\\s*\\]" "NC_POSTN(\\g<1>)" 0
[[NSNotificationCenter defaultCenter] postNotification:notif]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotificationName\\s*:\\s*(.*?)\\s*(.*?)\\s+object\\s*:\\s*nil\\s*\\]" "NC_POST(\\g<1>)" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotificationName\\s*:\\s*(.*?)\\s+object\\s*:\\s*nil\\s*\\]" "NC_POST(\\g<1>)" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotificationName\\s*:\\s*(.*?)\\s+object\\s*:\\s*(.*?)\\s*\\]" "NC_POSTO(\\g<1>, \\g<2>)" 0
[[NSNotificationCenter defaultCenter] postNotification:notif]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotificationName\\s*:\\s*(.*?)\\s+object\\s*:\\s*(.*?)\\s*\\]" "NC_POSTO(\\g<1>, \\g<2>)" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotificationName\\s*:\\s*(.*?)\\s+object\\s*:\\s*(.*?)\\s*\\]"
[[NSNotificationCenter defaultCenter] postNotification:notif]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotificationName\\s*:\\s*(.*?)\\s+object\\s*:\\s*(.*?)\\s+userInfo\\s*:\\s*(.*?)\\s*\\]"
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*postNotificationName\\s*:\\s*(.*?)\\s+object\\s*:\\s*(.*?)\\s+userInfo\\s*:\\s*(.*?)\\s*\\]" "NC_POSTOU(\\g<1>, \\g<2>, (\\g<3>))" 0
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*removeObserver:\\s*:\\s*(.*?)\\s+object\\s*:\\s*(.*?)\\s+userInfo\\s*:\\s*(.*?)\\s*\\]" "NC_REMN(\\g<1>, \\g<2>)" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*removeObserver\\s*:\\s*(.*?)\\s+name\\s*:\\s*(.*?)\\s+object\\s*:\\s*nil\\s*\\]" "NC_REMN(\\g<1>, \\g<2>)" 0
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*removeObserver\\s*:\\s*(.*?)\\s+name\\s*:\\s*(.*?)\\s+object\\s*:\\s*(.*?)\\s*\\]" "NC_REMNO(\\g<1>, \\g<2>, \\g<3>)" 0
[[NSNotificationCenter defaultCenter] removeObserver:tar name:nam object:obj]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_replace "\\[\\[NSNotificationCenter\\s+defaultCenter\\]\\s*removeObserver\\s*:\\s*(.*?)\\s*\\]" "NC_REM(\\g<1>)" 0
[[NSNotificationCenter defaultCenter] removeObserver:tar name:nam object:obj]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ search_grep "NC_REM\w*\\(.*?\\)"
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[[NSNotificationCenter defaultCenter] postNotificationName:nam object:obj userInfo:uInfo]
[[NSNotificationCenter defaultCenter] removeObserver:tar name:nam object:obj]
[[NSNotificationCenter defaultCenter] removeObserver:tar name:nam object:obj]
[[NSNotificationCenter defaultCenter] removeObserver:tar name:nam object:obj]
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 
[mazyod@Mazyads-MacBook-Pro:~/Developer/telly/Telly-iOS/TellyApp]$ 

Regex Disaster

It was such a painful lesson, almost as painful as my previous bash lesson, only mildly less awful.

Le me once wanted to write pretty bash code:

1
2
~$ var=5    # Ugly!
~$ var = 5  # better...

… Only to realize that the second line is an error. The script I was modifying was not through interactive shell, so I had no idea what is was throwing errors… Till this day, whitespace haunts me in my sleep.

As for the regex part, it was this:

1
regex = r"(?:.*\n.*){0, 3}"

This looks like a perfectly healthy regex expression, except that it is not. Adding that extra space within the braces made the whole thing break and produced unpredictable results. Don’t do that.



Event Dispatcher

A special post is happening this time, and it is a video! We will explore the new cocos2d-x Event Dispatcher, and how to use it as a replacement for CCNotificationCenter.

Without further ado:

Here are some relevent code snippets:

1
2
#define gEventDispatcher Director::getInstance()->getEventDispatcher()
#define NC_ADD(target, notif, handler) gEventDispatcher->addEventListenerWithSceneGraphPriority(EventListenerCustom::create(notif, handler), target);

Technological Lust

I grew up reading that lust is one of the deadly sins, but according to wikipedia, it can take many forms, including lust for knowledge, which is good, right?

I just got inspired to spill what is in my head and write about the tons of things I want to learn and try doing, so here it goes:

Haskell Game

You are not a programmer if you haven’t tried doing any functional programming. Actually, you can be, I was just exaggerating.

The premise is that functional programming is a new way to tackle programming problems and bends your thinking from looking at thing imperatively to another holistic view (I think).

I haven’t tried functional programming yet, and hence the idea of writing a game in Haskell.

Web Development / Ruby

I really wish I set some time aside and refactor my whole blog such that I know exactly how each and every thing works. After that, begins the fun of importing different frameworks and writing Ruby scripts for Octopress to streamline the process even more and make it awesome.

Cocos2d-X / Qt

I am already contributing to Cocos2d-X, but they seem to be interested in implementing a Mac client for the Cocos Studio, and it would be awesome if I can work on that. What would be even more awesome if I were to make it in Qt and make it multiplatform, while learning the Qt framework (since I am sick of the stupid Cocoa framework).

Pixel Art

I have started learning pixel art for a while, and abruptly stopped :( I need to get back to that..

Conclusion

Doesn’t look like much, actually!! Need to get serious about stuff.


Rant

I had this urge to just write a blog post, but don’t exactly know what to write about… Something broke along the way, I should be blogging like twice a day on average.

Anyways, let me see what should the first topic be…

Refactoring

I have been spending most of my extra energy refactoring the code I am working with at work. Some code hasn’t been visited since 2012, and I am just looking at the code, and I am thinking … “I have to understand what this does”. You see, you can’t really go into the flow state without a full clear idea of a macro perceptive of what you are working on.

Let’s track back a bit, I am saying too many things…

One, the flow state. You can only be truly productive if you enter this state. In order to enter this state, you need a clear goal, and very strong understanding of the work that has to be done. Basically, there is no flow state when you are just staring at the screen trying to understand something.

So, while I am looking around understanding code, I come across old code, which of course, is “bad” in terms of the current state of the project. Instead of enduring the pain of understanding the code, I go ahead and refactor it as well, so my future self, or other programmers don’t endure it, as well.

The process of refactoring is awesome because it actually allows you to enter the flow state even though you don’t understand the code, and you are trying to understand it! HOW?!

Let me pull a real example:

1
2
3
4
5
6
7
8
9
10
11
12
13
// FROM
[UIView animateWithDuration:1.6
                 animations:^{
                     dispatch_async(dispatch_get_main_queue(), ^{
                         int64_t delayInSeconds = 1500; //milliseconds actually
                         dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_MSEC);
                         dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                                [self doSomething];
                        });
                     });
                 }
                 completion:^(BOOL finished) {
}];

Anyways, this is code that hasn’t evolved as fast as the project.

So, while in complete focus, you see that the code is in dispatch_asyc, and then another dispatch is made. Obviously, we don’t need both, so BAM. Get rid of the outer async call.

Then, you see the milliseconds actually comment, and you simply rename that variable, and delete the comment. It’s a systematic process. You just apply what makes sense. Now, you got rid of that async call and useless comment.

Finally, you realize the delay can be added to the animateWithDuration call, and after you do that, the code doesn’t work anymore! You go into doSomething, and voala! There is another animateWithDuration call, and that’s why it didn’t work.

All this, as I mentioned, is systematic, and you can easily submit to the flow, and before you realize it, you have this code instead:

1
2
3
4
5
// TO
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
{
    [self doSomething];
});

Now, if anyone dares looks me in the eye and says refactoring is a waste of time, I’d probably lose hope in that individual’s future.

Yes, this is real code I dealt with.

Google Tag Manager

Because, why not?

Recently, I was asked to implement Google Tag Manager in our application for marketing purposes, and I’d like to share my thoughts on this beast.

We haven’t used it much, but my initial thought is.. WOW.

This beast is like a container for your “tags”. A tag is basically an addon that drives your application. This addon can be other apps, custom data, … you name it! All managed from a single slick web interface over at google’s website.

So, after integrating your app with GTM, all you have to do as a developer is deal with this single SDK! The powers it gives you are:

  1. Pull custom data from backend. (Customization)
  2. Integrate with apps on the fly. (AdWords, analytics, .. etc.)
  3. Manage container versions, and be backward compatible!

Yeah, it’s pretty darn awesome. Will post later how it actually performs, though.

Decorator Pattern

I made use of the decorator pattern, so I might as well share that! :D

The premise of the decorator pattern for GUI systems is that .. You decorate the base view with decorators! So, the decorator I wrote simply applies a “popup” effect, by rounding the corners and adding a close button at the top left corner.

Pretty neat stuff! Now, any view you want to show as a popup is developed independent of this aesthetic look… Truly awesome stuff. MUCH, MUCH better than the naive approach of “Uh, yeah, let’s just subclass”.

Reading

Opposed to my lack of blogging recently, I have been reading… and reading A LOT. If I am walking.. Just walking, and not responding to emails, whatsapps, … etc, I am reading something. To the point that, I walked the whole Mall of the Emirates back and forth to take a passport pic, and while walking, I finished 5 chapters of my book.

I am not sure it’s good or bad, but it’s sure productive! Walking is now coupled with reading, and is no longer irritating. Sometimes while walking, some (me) get affected by their surrounding negatively, and could flip their mood completely. But reading, and immersing yourself in that book instead of what’s around you, … is bad, actually. One ought to be more social than that…

Food

Without feeding, we can’t survive… Wait, wth am I writing! OK, I need to go eat .. NOW.

Conclusion

I like blogging… I wish people would blog more often, and especially people like Abdullah Al-Shalabi. Freaking awesome stuff he puts up on those posts.


Cocos2d-X v3

If you haven’t read the cocos2d-x forums yet, there has been a radical change to the cocos2d-x github repo. Basically, the team decided to abandon ship! No, they just moved from the develop branch to the new, shiny v3.

It wasn’t that bad of a migration for me. All I needed to do is follow the instructions in the post referenced above, and apply my own patches and changes. One issue was converting Point to Vec2… I mean… Whatever. Cocos should be renamed to something more meaningful if they aren’t gonna use ANY Cocoa conventions!!


A Challenge

I am collaborating on a iOS project, and the team is using Xcode. The issue with Xcode is that it doesn’t do any kind of #import management.

The challenge is to write a script that simply checks the import and searches the file for that class. If not present, remove that import. This is naive, since that imported file might contain other headers, variables, … etc, that are needed, but for the purposes of getting this over quickly, we will overlook that part.

5:11 pm: START!

Obviously it’s gonna be python…

5:16 pm:

Instead of defining a function that taken a path pointing to a file, I should make it take a string, so I can easily test it when I am done!

1
2
def clean_imports(file_contents):
    # stuff

5:24 pm:

I am slow… And I wish I used PyCharm for this, not sublime. Anyways, v0.0.0.1 is working!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import os
import re

def clean_imports(file_contents):
    """"""

    import_regex = re.compile(r'#import\s+"(\w+)\.h"')
    check_regex_raw = r"{}[^(\.h)]"

    all_classes = []
    for match in import_regex.finditer(file_contents):
        all_classes.append(match.group(1))

    print repr(all_classes)

clean_imports('#import "thisisatest.h" akdjsf a;ksldfj')

5:33 pm

I think it is done, and ready to be hooked with a “crawler”.

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
import os
import re

def clean_imports(file_contents):
    """"""

    import_regex = re.compile(r'#import\s+"(\w+)\.h"')
    check_regex_raw = r"{}[^(\.h)]"

    all_classes = []
    for match in import_regex.finditer(file_contents):
        all_classes.append(match.group(1))

    for klass in all_classes:
        check_regex = re.compile(check_regex_raw.format(klass))

        if not check_regex.findall(file_contents):
            file_contents = file_contents.replace(klass, klass + "NOTUSED")

        else :
            print repr(check_regex.findall(file_contents))

    print file_contents

clean_imports('#import "thisisatest.h" akdjsf a;ksldfj thisisatest ')

5:37 pm

Time to test!!

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
import os
import re

def clean_imports(file_contents):
    """"""

    import_regex = re.compile(r'#import\s+"(\w+)\.h"')
    check_regex_raw = r"{}[^(\.h)]"

    all_classes = []
    for match in import_regex.finditer(file_contents):
        all_classes.append(match.group(1))

    for klass in all_classes:
        check_regex = re.compile(check_regex_raw.format(klass))

        if not check_regex.findall(file_contents):
            file_contents = file_contents.replace(klass, klass + "NOTUSED")

        else :
            print repr(check_regex.findall(file_contents))

    return file_contents

if __name__ == "__main__":
    walk = os.walk(".")

    for dirname, dirs, files in walk:
        src_files = [x for x in files if x[:-2] in [".h", ".m"]]
        for afile in src_files:
            filepath = os.path.join(dirname, afile)
            with open(filepath) as f:
                contents = f.read()

            new_contents = clean_imports(contents)
            with open(filepath, "w+") as f:
                contents.write(new_contents)

5:43 pm

Tested… found so many bugs… Try to spot them. Time to run this beast!

5:48 pm

Fail. This is the worst idea I had ever. Xcode refused to compile anything when it saw the #import “blahblahUNUSED.h”. The premise was to comment it out type of deal, but it doesn’t work like commenting it out.

Need to revisit this later.

Conclusion

Whatever.. It was a nice exercise anyways.


Stand In

I am working on this credentials dialog where you would put a username/password, and then wait for things to happen with the backend. Obviously, I need some kind of loading indicator along with a cancel button.

The first thing is, how will I implement this? Assuming we don’t want to close the dialog, the most obvious and naive solution is to remove all views inside the dialog, and show the loading and cancel button. Other possible solutions that beat around that bush are there, but there is a much better solution.

Stand ins! A stand in is basically a way where you quickly swap the original thing with a replacement without anyone noticing. Movie actors due it all the time. You are watching the star riding this car, and all of a sudden he is jumping out of the car. The actual guy who jumps out of the car is a stunt man who stood in the star’s place!

Anyways, the idea of a stand in is to reduce the logic and complexity in the application, as well as promote reusability. If we implement the loading dialog as a stand in, it means that it is a separate component that can be used a lot of other places as well.


Over Gitting It

A guy once said, “You can never have enough of git”. Clearly he is mistaken, as I have completely overkilled it with the use of git for a mundane task, solved by much easier means.

There is this page in Humble Indie Bundle, that shows you your downloads, and you can switch between direct download and bit torrent. I wanted to know which downloads are only available as direct download.

Ding! My brain orders me to copy the list of direct downloads to a file, initialize a git repo, commit, replace the contents with the bit torrent downloads, check the diff for missing links.

After doing that, Mr. Jim gives another solution through diff. That reminds me how he praised that command in the past, but I never actually used it, which is probably why I completely forgot about it.

The ultimate answer, however, was to simply to highlight the list, switch to Bit torrent and back to direct downloads, then deselect. Now, the missing downloads from the bit torrent page should be highlighted!


Less is Better

Because of all the time I spent looking at other people’s code, using other people’s code, and simply writing damn code, it became quite rare for me to find good Objective-C I am not already aware of. Maybe I am not looking the right places, but that’s how it is.

Today, however, I found a new awesome practice that got me super excited and blogging once more.

Restrict and Defend!

When writing code, good code, always restrict and defend!

Access Denied

What I mean by restrict is to disable any behavior that external code might impose on your code in a way you have not meant for it to be. An example will make this crystal clear.

Let’s say you have a singleton class. In most languages that have sane constructors, you can easily declare the constructor as private and you are all set. External code can’t instantiate the singleton, and can only access the shared instance. We can’t do that in objective-c, but here is what we can do:

1
- (id)init __attribute__((unavailable));

This marks the init method with an unavailable attribute so external classes cannot instantiate an instance. I would take this a step further, and mark the +[NSObject new] method as unavailable, as well.

I know, Mr. Smarty Pants, the caller can easily work around this using performSelector: or even casting to id, but all we have to do, really, is throw an exception in the init method, and use another init for our internal use.

Put Up Those Defenses!

As for defending, it is the practice of validating parameters passed to your objects. The simplest defense is NSParameterAssert, which asserts that the parameter passed is not nil. You would want to use that when you absolutely need a parameter to be a valid, non-nil value.

Other defenses can be set up using NSAssert by validating strict assumptions you are making about the passed objects.

Conclusion

They say less is more. In our case, less is more and even better.


Binary, Or Not!

One of the terminal scripts that I heavily use is the search and replace script. It simply searches for occurrences of a string, and highlights the results in terminal. You can optionally choose to replace that string with something else.

In any case, it caused me a lot of headaches and unnecessarily slowed down the search when the script scanned binary files. Not only is it not useful to search those files, but the binary can easily corrupt if we replace something in it by mistake.

It is unfortunate that python doesn’t seem to have a library included that solves this issue, but thankfully pypi has the answer.

binaryornot

Talk about originality, eh? binaryornot is a very simple module that serves the purpose of detecting whether a file or string is binary. I have no idea how it internally works, but it gets the job done:

1
2
3
4
5
# Import the check module, and name it something more relevant.
from binaryornot import check as bcheck

if not bcheck.is_binary(pathToFile):
    # Do the search!

Simple, and super handy.

Conclusion

I love python, and dream that one day I can talk python with other people.


Validate Your Assumptions

When working with a scripting language like python, it is so awesome how easily you can test your assumptions or experiment with module. You simply launch terminal, go into python’s interactive interpreter and you test to your heart’s content.

What about iOS apps?

As far as my Google ship sailed, I couldn’t find anything solid. People always recommended starting a new project in Xcode and doing stuff there.

Well, what I came here to say is, I will probably use this approach as my second debugging step. The first debugging step is simply using the interactive console to dump the variables and see if anything looks awkward.

It may seem like an overkill to create a new project and build the setup to test something, but in most cases it’s probably not. The freedom to focus on a single component in the project rids you of having to worry about other code affecting the component’s behavior. It also gives you the perfect environment to further explore and learn more about the component, by iterating quickly with the fresh project.

Conclusion

This was probably a useless rant for the sake of writing a blog post today, and not falling behind.


Unity So Far

If I had a choice, I’d go back to cocos in a blink of an eye. It’s is so unfortunate that the conditions of out team forces us to use Unity (it is mainly artists and designers), as well as the fact that, well… The freakin game is in 3D! So, Unity is the only feasible solution for our needs…

Animation States

I ran into this weird and super annoying issue in my very first Unity game, which is dead simple! Actually, make that two weird issues.

The Any State

When setting up an animation in Unity, there is a convenient “Any State” block that allows you to transition to a state from any other state. The obvious need for this is the death animation state, which can occur at any given time.

Believe it or not, when you set a condition to move to transition from the “Any State”, it also includes the state you just transitioned to!!

“What do you mean?”

Adding a transition to the “death” state from “Any State” using a condition like “if isDead is true”, will cause the animator to transition from whatever state to the death state, and then transition from the death state to itself as long as the isDead is still evaluating to true!! ლ(ಠ益ಠლ)

Atomicity

Animation transitions created are atomic by default, i.e. they cannot be interrupted. So, when you have a player banging on the keyboard, and you are using the “Any State” explained above, you have a serious problem.

Since the “Any State approach” requires you to reset the condition after transitioning, what I did was simply:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Update()
{
    // update animator (Stupid transition from any state includes current state -_-")
    int heading = CalculateHeading(horizontalInput, verticalInput);

    if (heading != previousHeading)
    {
        anim.SetInteger("direction", heading);
        previousHeading = heading;
    }
    else
    {
        anim.SetInteger("direction", -heading);
    }
}

Looks good to me. Set the integer, and on next update clear it, and so on… Not so fast there, buddy. Remember that talk about atomicity? Well, even if you freakin turn it off, the transition still cannot be interrupted >__<. That is to say, if you do “transition to x, transition to y, stop” fast enough, the transition to y will never happen!

I really don’t want to explain this again, please see my stackOverflow question

Conclusion

Don’t sweat it… As long as Unity enables you to achieve your goal, endure it like a women would endure a delivery to see the smile of her child… Saying that felt so weird.


The Quiz

The Quiz

You have these numbers at your disposal:

1
1, 3, 5, 7, 9, 11, 13, 15

use them, with repetition, to make the following expression evaluate to true:

1
__ + __ + __ + __ + __ = 30

Solution

What I naturally did was:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def all_combos(arr, result):
    """"""

    if len(result) == 5:
        if sum(result) == 30:
            print result
    else :
        for x in arr:
            new_result = result[:]
            new_result.append(x)

            all_combos(arr, new_result)


available_numbers = range(1, 16)[::2]

all_combos(available_numbers, [])

Which gave no solutions at all…

So I raged at the person who gave the question, and they replied:

Dude, there is no way you can add odd numbers an odd number of times, and get an even number. That’s the real solution.

Conclusion

Ever heard of the “Helicopter Approach”? Well, you should read about it.


Gmail Filters

It seems inevitable that once you start using GitHub seriously, you run into this issue where you just get overwhelmed by the number of emails sent in a single hour. It also gets distracting and annoying when you just don’t have the time to go over them, and need to see everything else.

That’s where Gmail filters come into place.

It is probably an ancient concept that is widely used in the developed countries, but for a developing county, emails where never our thing. “MSN” was. That caused us to be less interested in investing time organizing our inbox, and more interested in changing our profile pictures and status messages on IM clients.

(Note to you youngsters, MSN was what we called all IM services, which was only MSN initially, then GTalk, … etc. “Let’s chat on google’s MSN!” was a common phrase.)

The Filters

Setting them filters is super easy, and convenient. After going to the gmail web app, just search for the pattern of emails you want to filter. It should update the view to show you the result. You can use this to validate your search query. After that, click the small gray arrow next to the search button, and choose “create filter from search”. Le Done.

Conclusion

Stop allowing your valuable time to be slowly consumed by all those emails that you don’t need to see immediately. That especially applies when you are at work, or in the mood to do great things. This will come in handy.


Unity

Shit is getting real (⌐■_■). I started looking into Unity (again), and this time round, there is no backing out.

There were a lot of flaws in my previous approach to learn Unity. I tried desperately to ignore the editor and code everything, as I would normally do in cocos2d. That caused major nightmares and headaches, and me giving up eventually.

Not anymore. The first thing to master is not C#, but the editor instead. Starting with Unity website’s awesome tutorial line up, I think I learned a lot more than I would have if I were to just desperately try to get a game up and running just through code.

With the editor basics out of the way, I think I’ll just go ahead and run through the rest of the tutorial for the time being, and then implement a dead simple game from scratch to test what I learned.

Conclusion

This is a mark in history of when I started taking Unity seriously. I am not sure where it will end, but I sure hope it ends well, since it’s taking lots of time learning, and other projects are being delayed because of this >_<.


Memory Preallocation

No, no, I am not referring to the pooling of high-level objects and caching them, that’s child’s play. I am referring to hard core C level memory preallocation, slicing, and pooling.

What I’ll do is, I’ll run through the thought process I went through, and that should give the best perspective to the reader about how this works.

Wait, Why?

I did mention this in a post from long, long ago. Read it up.

The Problem Statement

Thankfully, we have a lot of constraints that makes this problem a lot easier than it would have been if they weren’t there. I am taking advantage of most of the constraints, but not all, unfortunately.

The problem is:

Preallocate and reuse blocks of memory that would service a single type of object, which is the GameState object.

Sweet! So, the size of the objects are all the same, since they are of the same type! That makes things a lot easier. There is also the fact that they are allocated and freed in a LIFO fashion, but I didn’t rely on that property, which could’ve simplified things even more.

The Block Of Memory

So… What is this block of memory? Should be easy! Just an array of whatever the type of objects we want to create!

1
memBlock = malloc(sizeof(GameState)*preallocate);

Cool. Now, we have our memory block.

The Tracking

We need to track which memory blocks are available and which are not! Again, if I were to use the fact that I am doing DFS in my code, I can easily do the tracking using a single index that tells me how much of the memory block is consumed. Whenever a block is returned to the pool, it has to be the last block, since it’s LIFO…

(OK, I just went to check the code, and found something that bothered me, so I fixed it, then in turns out due to recent changes, the game is crashing, so I fixed that as well…)

I really need to make use of the LIFO property… It makes things a lot simpler, but anyway.

So, we are assuming that the memory is returned to us in random order. For example, we provide blocks 0, 1, 2, 3, and then block 2 is returned to us, while 3 is still being used. Hence, the requirement of a more detailed tracking.

The way I implement this is by creating an array of pointers. Pointers to what? GameState, of course!

1
memPtrStack = malloc(memPtrStack, sizeof(GameState *)*preallocate;

The first thing I do, is initialize this array of pointers to point to the respective index in the memory blocks array:

Then, let’s say three requests came in for memory blocks. We move the index by three, and “give” those pointers to the caller:

Finally, when the pointer is suppose to be freed, who ever called the alloc must give use the pointer back so we add it into the pointer stack, and that block will be available again for the next time alloc is called:

The Expansion

OK, if you think the above was a bit lame, I don’t blame you. That was super basic stuff. The fun kicks when when we want to expand the memory.

A request for a memory block comes in, but we already gave out all the memory blocks! What should we do!! Expand the memory block, obviously. I wish we could use realloc, but we can’t.

The most painless way is to probably do the following:

First, instead of allocating an array of memory blocks that is assigned to the memBlock variable, we change the variable to memBlocks, and make it an array to and array of memory blocks:

1
2
memBlocks = realloc(memBlocks, sizeof(GameState *)*(index+1));
memBlocks[index] = malloc(sizeof(GameState)*preallocate);

So, on every expansion, we bump the number of blocks allocated, and dynamically increase the size of the memBlocks array with realloc, and then assign the newly created space to a memory block.

Of course, with the new block available, we expand the memPtrStack and add pointer of the newly created blocks. (I won’t add the code, since it is ugly. I need to fix it).

Why we can’t use realloc:

It would have been so awesome if the use of realloc was possible, but it isn’t. What realloc does is request more contiguous memory, but the currently memory block allocated might not have any free memory beside it! In those cases, realloc needs to copy the current memory to another location, while allocating the new required space as well.

Since we are sending pointers to the callers, moving the underlying memory will make those pointers point to a memory address no longer managed by us!! Hello EXC_BAD_ACCESS.

The Performance

I haven’t really tested the performance of this versus the non prealloc’s performance, but I really want to do that soon. I already have the benchmarks from the Objective-C bot, and the non prealloced C bot on this page. I need to run the non prealloced tests again, since I moved to static libraries and cocos2d-x, which may or may not affect performance. Then, I can safely do the prealloc tests.

Now, if this prealloc thingie gives me another major boost, I can probably implement an AI that can easily beat top Dama players without breaking a sweat :D

Conclusion

It kills me that this hasn’t made it to my game’s update yet…. IT KILLS ME.


Android Static Libraries

I have had some grief trying to link the AI library of my game with the cocos2d-x game. Most of the grief was due to a silly, silly mistake from my end.

First, I didn’t immediately realize that I need to compile the library for Android, as I tried to link it against the iOS library. I quickly realized how silly this was, so I went on a journey on how to compile static libraries for Android.

It wasn’t bad. All I had to was provide an Android make file with the build steps, and an application make file with the supported architectures. Then, I had to plug these to a dummy project, so the make file gets triggered or something.

That was pretty easy, especially with the samples provided with the NDK. I replaced one of the samples organs with my things, and it compiled the thing! Hurray!

Then begins my nightmare…

As I tried to link it against my game, I used some reference online, which is to simply do the following:

1
2
3
4
5
6
7
8
include $(CLEAR_VARS)

LOCAL_MODULE := my_static_lib
LOCAL_SRC_FILES := ../../lib/MyLib/$(TARGET_ARCH_ABI)/libMyLib.a

include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

This is probably the first thing I tried, and it gave me errors about missing symbols… WHAT?! I freak out and use nm command, and it shows that the library doesn’t have any symbols… “GREAT! THE BUILD SYSTEM IS BROKEN”, I cried in rage. As I hopelessly spend hours trying to figure the source of the problem, I keep telling myself: “It’s working on iOS, why not android? Because the build toolchain is broken”. If something like that was broken, someone ought’ve noticed… /facepalm.

After posting on stackOverflow, a guy told me how the nm command doesn’t work on these libraries, and I should use the binaries provided by the ndk to check, which I did. The symbols were all there…. WHAT?!

I kind of lost hope there… So, I took all the source files and included them into the project directly. No more static library linkage… Oh wait, but there is more.

As I added the source files, the iOS no longer compiled, and complained about missing symbols!! As I looked closely, I laughed hysterically at my silly, silly mistake…

So, in the code, which I only built for iOS up until now, it was using an old version of the library, and when I added the most recent source files, it threw errors, since in the up-to-date source I had done major function name changes…

While biting my lips, I updated the code to the newer APIs, and decided to build the libraries again. Voilla, it worked like a charm.

tl;dr: iOS was linked against an old library, android was linked against a new library, code was referencing older library API, Android failed to build, I laughed hysterically at one point.

Conclusion

Again… Think clearly, identify the root problem properly, don’t making any friggin assumptions.