IOS-检测blobck中self

1458973781558646.jpg

在iOS开发中我们经常用到block,无论是GCD还是参数传递,block都是一个很不错的选择。然而有利也有弊,block会产生循环引用,但是这代码通常不会报错,只是运行结果不正确!于是花费大量时间打断点调试,发现原来问题在这里:

1
2
3
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
            self.view.backgroundColor = [UIColor redColor];
     });

这里的block中用了self,导致viewcontroller不能调dealloc,每次被这个坑了的时候,内心都几乎是崩溃的...... 于是写了个脚本来检测这个问题,效果大大的好。

以下是正题

block长什么样?它大概长这样子:一个^后面有{和},介于此我们就能查到几乎所有代码里面的block了,那么block里面的self怎么识别?weakSelf算吗,当然不算,按照语法:如果一个self字段它的前后都不是字母数字下划线(好好理解下这句话),那它就是我们要找的self。按着这个思路block里面的self便无所遁形了。然后按着如下写脚本(代码在文末):

  1. 遍历工程里面的所有.m文件

  2. 查找^

  3. 匹配后面的一对{}记住位置

  4. 查找{}里面符合规则的self

  5. 调用mac的通知中心通知自己哪里有问题

最终效果如下:

1458977425920371.png

想要调用mac的通知中心,首先需要pyobjc库,安装后脚本就可以正常运行了,需要设置的参数如下:

1.projectPath(工程所在路径)

如:projectPath = "/Users/yuyang/Documents/techwolf/mobile_ios"

2.noPath(不检测路径)

如:noPath = ['ThirdLibs','iosTools']或:noPath = None(检测工程下所有路径)

如果这样用你觉得用着麻烦(毕竟每次都要开着终端),那么可以用炮筒机器人来减轻工作量,炮筒机器人是mac自带的就是这个:

1458977606178029.png

首先打开它

1458977791411741.png

把它拖到右面的工作区,然后选择python脚本

80.png

清除里面的内容,把脚本的代码拷贝进去,最后生成这个app:

1458977981606280.png

当然你也可以设置这个为开机启动项。

运行时的效果这样:

QQ截图20160328161917.png

脚本
# -*- coding: utf-8 -*-

import sys
import os
import Foundation
import objc
import AppKit
from datetime import date, time, datetime, timedelta

#工程路径
projectPath = "/Users/stone/Documents/Document/许愿灯_任务优化版1/bluesharktv"
#不检测路径
noPath = ['ThirdLibs','iosTools']
#False:检测所有,True:不检测不检测路径和动画产生的self
NormalCheck = True

def notify(self, title, subtitle, text, url):
    NSUserNotification = objc.lookUpClass('NSUserNotification')
    NSUserNotificationCenter = objc.lookUpClass('NSUserNotificationCenter')
    notification = NSUserNotification.alloc().init()
    notification.setTitle_(str(title))
    notification.setSubtitle_(str(subtitle))
    notification.setInformativeText_(str(text))
    notification.setSoundName_("NSUserNotificationDefaultSoundName")
    notification.setHasActionButton_(True)
    notification.setOtherButtonTitle_("View")
    notification.setUserInfo_({"action":"open_url", "value":url})
    NSUserNotificationCenter.defaultUserNotificationCenter().setDelegate_(self)
    NSUserNotificationCenter.defaultUserNotificationCenter().scheduleNotification_(notification)
    
def userNotificationCenter_didActivateNotification_(self, center, notification):
    userInfo = notification.userInfo()
    if userInfo["action"] == "open_url":
        import subprocess
        subprocess.Popen(['open', userInfo["value"]])
        
def runTask(func, day=0, hour=0, min=0, second=0):
  # Init time
  now = datetime.now()
  strnow = now.strftime('%Y-%m-%d %H:%M:%S')
  print "now:",strnow
  # First next run time
  period = timedelta(days=day, hours=hour, minutes=min, seconds=second)
  next_time = now + period
  strnext_time = next_time.strftime('%Y-%m-%d %H:%M:%S')
  print "next run:",strnext_time
  while True:
      # Get system current time
      iter_now = datetime.now()
      iter_now_time = iter_now.strftime('%Y-%m-%d %H:%M:%S')
      if str(iter_now_time) == str(strnext_time):
          # Get every start work time
          print "start work: %s" % iter_now_time
          # Call task func
          func()
          print "task done."
          # Get next iteration time
          iter_time = iter_now + period
          strnext_time = iter_time.strftime('%Y-%m-%d %H:%M:%S')
          print "next_iter: %s" % strnext_time
          # Continue next iteration
          continue
          
#get all files
def scan_files(directory,prefix=None,postfix=None,exceptPath=None):
    files_list=[]
    def addStr(path):
        if exceptPath:
            count=0
            for pathString in exceptPath:
                if int(path.find(pathString))==-1:
                    count+=1
            if count == len(exceptPath):
                files_list.append(path)
        else:
            files_list.append(path)

    for root, sub_dirs, files in os.walk(directory):
        for special_file in files:
            if postfix:
                if special_file.endswith(postfix):
                    addStr(os.path.join(root,special_file))
            elif prefix:
                if special_file.startswith(prefix):
                    addStr(os.path.join(root,special_file))
            else:
                addStr(os.path.join(root,special_file))

    return files_list
    
#remove note
def removeNote(content):
    text = content
    for i in range(0,len(text)):
        if i+1<len(text):
            if text[i]=="/" and text[i+1]=="/":
                text = text[:i] + text[text.find('\n',i):]
                i=text.find('\n',i)
    for i in range(0,len(text)):
        left = text.find('/*',i)
        right = text.find('*/',i)
        if left>0 and right>0 and right>left:
            line = ''
            for j in range(left,right):
                if text[j]=='\n':
                    line = line + '\n'
            text =  text[:left] + line + text[right:]
            i=right
            left = -1
            right = -1
    return text
    
#tell weather is legal or not
def isLegal(content):
    if content=='_' or content.isdigit() or content.isalpha():
        return False
    return True
    
#get file content
def getFileContent(path):
    if path.strip()=='':
        print 'error------------>path is empty'
        return
    file_object = open(path)
    try:
        all_the_text=file_object.read()
        all_the_text=removeNote(all_the_text)
        i = int(all_the_text.find('^'))
        if i > -1 and i < len(all_the_text):
            print("--------------in File:" + path + "---------------")
            i=0
            lastTemp=0
            while (i<len(all_the_text)):
                temp = int(all_the_text.find('^',i+1,len(all_the_text)))
                if NormalCheck :
                    if temp > -1:
                        if all_the_text[temp-11:temp] == 'animations:':
                            temp=-1
                        if all_the_text[temp-11:temp] == 'completion:' and all_the_text[temp+1:temp+16] == '(BOOL finished)':
                            temp=-1
                if temp == -1 or temp == lastTemp:
                    break
                if temp + 1 < len(all_the_text):
                    if all_the_text[temp+1] == ')':
                        break
                if temp > -1 and temp<len(all_the_text):
                    leftCount=0
                    rightCount=0
                    tempLeft=0
                    tempRight=0
                    lastNum=0
                    for j in range(temp,len(all_the_text)):
                        if all_the_text[j]=='{':
                            leftCount+=1
                            if tempLeft==0:
                                tempLeft=j
                        if all_the_text[j]=='}':
                            rightCount+=1
                            tempRight=j
                        isRightBlock=True

                        if all_the_text.find('@implementation',temp,tempLeft)>-1 and tempLeft>0 and tempRight>tempLeft:
                            isRightBlock=False
                        if leftCount > 0 and rightCount > 0 and leftCount==rightCount and isRightBlock:
                            while(tempLeft < tempRight):
                                k=all_the_text.find('self',tempLeft,tempRight)
                                if k>0 and isLegal(all_the_text[k-1]) and isLegal(all_the_text[k+4]):
                                    num=1
                                    for m in range(0,k):
                                        if all_the_text[m]=='\n':
                                            num+=1
                                    if num>lastNum:
                                        outputStr = 'num:' + str(num) + ' maybe have self !!!!!'
                                        print outputStr
                                        notiStr = path.split('/')[len(path.split('/')) - 1] + '\n' + outputStr
                                        notify('self',title='maybe have self',subtitle=path,text=notiStr,url='')
                                        lastNum=num
                                tempLeft+=4
                            tempLeft=0
                            tempRight=0
                            leftCount=0
                            rightCount=0
                            break
                    i=temp
                    lastTemp=temp

    finally:
        file_object.close()
    return
    
#get the path
def start():
    print("===============path==============")
    print(projectPath)
    #get all files
    excPath=None
    if NormalCheck:
        excPath=noPath
    files_list=scan_files(projectPath,postfix=".m",exceptPath=excPath)
    print("=============all " + str(len(files_list)) + " files==========")
    for filePath in files_list:
        print filePath
    print("==============================================================")
    for filePath in files_list:
        getFileContent(filePath)

start()
runTask(start, day=0, hour=0, min=10,second=0)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值