Skip to content

Instantly share code, notes, and snippets.

@JohnWong
Last active August 29, 2015 14:05
Show Gist options
  • Save JohnWong/d75adad722dce2bdf34b to your computer and use it in GitHub Desktop.
Save JohnWong/d75adad722dce2bdf34b to your computer and use it in GitHub Desktop.
Objective-C Block Checker
#coding=utf-8
import argparse
import re
import sys
import os
reload(sys)
sys.setdefaultencoding('utf8')
class BlockChecker:
selfregex = re.compile('.*[([ \t]self[ .]')
def readfile(self, filepath):
with open(filepath, "r") as fp:
content = fp.read()
return content
def filtercomment(self, content):
coderesult = ''
status = 0
for ch in content:
if status == 0:
if ch == '/':
status = 1
else:
coderesult += ch
elif status == 1:
if ch == '*':
status = 2
elif ch == '/':
status = 5
else:
coderesult += '/' + ch
status = 0
elif status == 2:
if ch == '*':
status = 4
else:
status = 3
if ch == '\n':
coderesult += '\n'
elif status == 3:
if ch == '*':
status = 4
elif ch == '\n':
coderesult += '\n'
elif status == 4:
if ch == '/':
status = 0
elif ch != '*':
status = 3;
if ch == '\n':
coderesult += '\n'
elif status == 5:
if ch == '\n':
status = 0
coderesult += ch
return coderesult
pass
pass
def filterblock(self, content):
status = 0
blocks = []
code = ''
linenum = 1
for ch in content:
if ch == '\n':
linenum += 1
if status == 0:
if ch == '@':
status = 1
elif ch == '(':
status = 3
elif ch == '^':
blockstart = linenum
status = 4
elif status == 1:
if ch == '"':
status = 2
else:
status = 0
elif status == 2:
if ch == '"':
status = 0
elif status == 3:
if ch == ')':
status = 0
elif status == 4:
if ch == '{':
status = 5
elif status == 5:
if ch == '}':
blockend = linenum
blocks.append([code, blockstart, blockend])
status = 0
else:
code += ch
return blocks
def iscontainself(self, blockcode):
iterator = self.selfregex.search(blockcode)
return iterator != None
def checkfile(self, filepath):
content = self.readfile(filepath)
code = self.filtercomment(content)
blocks = self.filterblock(code)
result = []
for block in blocks:
if self.iscontainself(block[0]):
result.append(block[1:])
return result
def printitemtoxcode(self, filePath, lineNum):
print("%s:%d: %s: %s" % (filePath, lineNum, "warning", "self in block may cause memory leak."))
def printtoxcode(self, result):
for (key, value) in result.items():
for block in value:
self.printitemtoxcode(key, block[0])
pass
def getsourcefiles(self, rootpath, suffix):
file_list = []
if rootpath is None:
raise Exception('rootpath is None')
for dirpath, dirnames, filenames in os.walk(rootpath):
for name in filenames:
if name.endswith(suffix + '.m'):
filepath = dirpath + os.sep + name
file_list.append(filepath)
return file_list
def printresult(self, result):
print('Find ' + str(len(result)) + 'instances')
multiprint('=')
for (key, value) in result.items():
print(key)
lines = ''
for block in value:
lines += str(block[0]) + '-' + str(block[1]) + ' '
print(lines)
multiprint('-')
def check(self, rootpath, suffix):
filelist = self.getsourcefiles(rootpath, suffix)
result = {}
for filepath in filelist:
fileresult = self.checkfile(filepath)
if len(fileresult) > 0:
result[filepath] = fileresult
self.printtoxcode(result)
return result
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Check ViewController Xcode project to find self in block code ')
parser.add_argument('path', help='Objective-c source root.')
parser.add_argument('-suffix', help='Objective-c class file suffix. Default is "Controller".', default='Controller')
args = parser.parse_args()
rootpath = args.path
suffix = args.suffix
blockChecker = BlockChecker()
result = blockChecker.check(rootpath, suffix)
@JohnWong
Copy link
Author

Check whether self appeared in blocks of a UIViewController. This may cause memory leak.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment