生成 objc 垃圾代码

非完整版,本来是打算用来应对苹果审核 4.3 被拒的,后面莫名其妙的过审了 (随便改了改 UI),暂且搁置了

目前版本只是简单的搭了一下基本的生成规则,当做 Python 练习了

  • 随机生成类文件(.h/m)
  • 随机生成属性并初始化
  • 随机生成方法/方法体并实现调用
  • 生成垃圾文件包对应的 Headers 文件

Gitee 源码地址


Python

调试环境: Python 3.9.6

import random
import string
import os

# 当前文件目录
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

# 关键字配置文件
KEYWORDS_FILE = CURRENT_DIR + "/keywords.txt"

# 类前缀
CLASS_PRE = "Test"

# 随机生成多少个类文件
FILE_NUM = 100

# 文件导出目录
OUTPUT = CURRENT_DIR + "/output/" + CLASS_PRE


void = 0
NSString = 1
NSInteger = 3
NSNumber = 4
BOOL = 5
double = 6
NSArray = 2
NSDictionary = 7
UIView = 8
UIFont = 9

def objc_type_name(type):
    if type == void:
        return "void"
    if type == NSString:
        return "NSString *"
    if type == NSInteger:
        return "NSInteger "
    if type == NSNumber:
        return "NSNumber *"
    if type == BOOL:
        return "BOOL "
    if type == double:
        return "double "
    if type == NSArray:
        return "NSArray *"
    if type == NSDictionary:
        return "NSDictionary *"
    if type == UIView:
        return "UIView *"
    if type == UIFont:
        return "UIFont *"
        
        
def random_objc_property_value(type):
    if type == void:
        return ""
    if type == NSString:
        v = f"{random_keywords()}{str(random.randint(0, 10000))}{random_keywords()}"
        return f"@\"{v}\""
    if type == NSArray:
        return "@[]"
    if type == NSInteger:
        return str(random.randint(0, 10000))
    if type == NSNumber:
        return f"@{random.randint(0, 10000)}"
    if type == BOOL:
        return "YES" if random.randint(0, 1) == 1 else "NO"
    if type == double:
        return str(random.randint(0, 10000))
    if type == NSDictionary:
        return "@{}"
    if type == UIView:
        return "[UIView new]"
    if type == UIFont:
        return f"[UIFont systemFontOfSize:{random.randint(9, 30)}]"
    return "nil"


class ObjcProperty:
    def __init__(self):
        self.name = ""
        self.type = 0
        self.ref = ""
        self.typename = "NSString *"
        
    def Random():
        result = ObjcProperty()
        
        name = random_keywords()
        if random.random() < 0.1:
            name = f"{name}_{random_keywords()}"
        if random.random() < 0.1:
            name = f"{name}_{random_keywords()}"
        if random.random() < 0.1:
            name = f"{name}_{random_keywords()}"
        name = underscore_to_camelcase(name,True)
        
        result.name = name
        result.type = random.randint(1, 9)
        result.typename = objc_type_name(result.type)
        if result.type == NSString:
            result.ref = "strong"
        if result.type == NSInteger:
            result.ref = "assign"
        if result.type == NSArray:
            result.ref = "strong"
        if result.type == NSNumber:
            result.ref = "strong"
        if result.type == BOOL:
            result.ref = "assign"
        if result.type == double:
            result.ref = "assign"
        if result.type == NSDictionary:
            result.ref = "strong"
        if result.type == UIView:
            result.ref = "strong"
        if result.type == UIFont:
            result.ref = "strong"
        return result


class ObjcFunc:
    def __init__(self):
        self.name = ""
        self.type = 0
        self.returntype = 0
        self.params = [] # ObjcProperty
        self.fullname = ""
        self.run = ""
        
    def Random():
        result = ObjcFunc()
        name = random_keywords()
        name = f"{name}_{random_keywords()}"
        name = f"{name}_{random_keywords()}"
        if random.random() < 0.3:
            name = f"{name}_{random_keywords()}"
        if random.random() < 0.6:
            name = f"{name}_{random_keywords()}"
        if random.random() < 0.9:
            name = f"{name}_{random_keywords()}"
        name = underscore_to_camelcase(name,True)
        result.name = name
        for i in range(0, random.randint(0, 5)):
            result.params.append(ObjcProperty.Random())
        result.type = random.randint(0, 1)
        result.returntype = random.randint(0, 8)
        fullname = ""
        if result.type == 0:
            fullname = f"{fullname}- "
        if result.type == 1:
            fullname = f"{fullname}+ "
        fullname = f"{fullname}({objc_type_name(result.returntype).rstrip()})"
        fullname = f"{fullname}{result.name}"
        for i in range(0 ,len(result.params)):
            p = result.params[i]
            typename = p.typename.rstrip()
            if i == 0:
                fullname = f"{fullname}:({typename}){p.name} "
            else:
                fullname = f"{fullname}{p.name}:({typename}){p.name} "
        fullname = fullname.rstrip()
        result.fullname = fullname
        return result


class ObjcClass:
    def __init__(self):
        self.name = ""
        self.supertype = 0
        self.supername = "NSObject"
        self.importH = "#import <UIKit/UIKit.h>"
        self.func = []
        self.property = []
        self.output = ""
        self.link = [] # ObjcClass
        
    def contains_property(self,property):
        for obj in self.property:
            if obj.name == property.name:
                return True
        return False
    
    def Random():
        result = ObjcClass()
        result.name = random_class_name()
        for i in range(0, random.randint(0, 30)):
            p = ObjcProperty.Random()
            if result.contains_property(p) == False:
                result.property.append(p)
        for i in range(0, random.randint(0, 30)):
            result.func.append(ObjcFunc.Random())
        result.supertype = random.randint(0, 2)
        if result.supertype == 0:
            result.supername = "NSObject"
            result.importH = "#import <UIKit/UIKit.h>"
        if result.supertype == 1:
            result.supername = "UIViewController"
            result.importH = "#import <UIKit/UIKit.h>"
        if result.supertype == 2:
            result.supername = "UIView"
            result.importH = "#import <UIKit/UIKit.h>"
        result.output = OUTPUT
        return result
        
    def export(self):
        # 生成 .h 文件
        self.exportH()
        # 生成 .m 文件
        self.exportM()
        
    def exportH(self):
        code = ""
        code = random_enter_for(code)
        code = f"{code}{self.importH}\n"
        code = f"{code}\n"
        code = f"{code}NS_ASSUME_NONNULL_BEGIN\n\n"
        code = random_enter_for(code)
        code = f"{code}@interface {self.name} : {self.supername}\n"
        code = random_enter_for(code)
        for p in self.property:
            code = f"{code}@property ({p.ref} ,nonatomic) {p.typename}{p.name};\n"
            code = random_enter_for(code)
        code = f"{code}\n"
        code = random_enter_for(code)
        code = random_enter_for(code)
        for f in self.func:
            code = f"{code}{f.fullname};\n"
            code = random_enter_for(code)
        code = f"{code}@end\n\n"
        code = f"{code}NS_ASSUME_NONNULL_END"
        code = random_enter_for(code)
        file = open(f"{self.output}/{self.name}.h", "w")
        file.write(code)
        file.close()
        
    def exportM(self):
        code = ""
        code = random_enter_for(code)
        code = f"{code}#import \"{self.name}.h\"\n"
        for obj in self.link:
            if obj.name != self.name:
                code = f"{code}#import \"{obj.name}.h\"\n"
        
        code = f"{code}\n"
        code = random_enter_for(code)
        code = f"{code}@implementation {self.name}\n"
        code = random_enter_for(code)
        
        code = f"{code}- (instancetype)init {{\n"
        code = f"{code}    self = [super init];\n"
        code = f"{code}    if (self) {{\n"
        
        for p in self.property:
            code = f"{code}        _{p.name} = {random_objc_property_value(p.type)};\n"
            code = random_enter_for(code)
            
        for obj in self.func:
            sender = "self" if obj.type == 0 else self.name
            full_run_func = f"{sender} {obj.name}"
            for i in range(0 ,len(obj.params)):
                p = obj.params[i]
                if i == 0:
                    full_run_func = f"{full_run_func}:{random_objc_property_value(p.type)} "
                else:
                    full_run_func = f"{full_run_func}{p.name}:{random_objc_property_value(p.type)} "
            full_run_func = full_run_func.rstrip()
            code = f"{code}        [{full_run_func}];\n"
            code = random_enter_for(code)
        
        code = f"{code}    }} return self;\n"
        code = f"{code}}}\n\n"
        code = random_enter_for(code)
        
        for obj in self.func:
            if obj.returntype == void:
                code = f"{code}{obj.fullname} {{\n\n}}\n"
            else:
                code = f"{code}{obj.fullname} {{\n    return {random_objc_property_value(obj.returntype)};\n}}\n"
        
        code = f"{code}@end\n"
        file = open(f"{self.output}/{self.name}.m", "w")
        file.write(code)
        file.close()
        
    def random_func_from_link(self):
        obj = random.choice(self.link)
        return random.choice(obj.func)
        
        
# 生成随机类名
def random_class_name():
    result = ""
    result = f"{result}_{random_keywords()}"
    if random.random() < 0.8:
        result = f"{result}_{random_keywords()}"
    if random.random() < 0.4:
        result = f"{result}_{random_keywords()}"
    if random.random() < 0.2:
        result = f"{result}_{random_keywords()}"
    if random.random() < 0.3:
        result = f"{result}_controller"
    result = underscore_to_camelcase(result)
    result = f"{random_pre()}{result}"
    return result
    
# 类前缀
def random_pre():
    return CLASS_PRE

# 随机在尾部插入换行符
def random_enter_for(code):
    if random.random() < 0.2:
        code = f"{code}\n"
    return code
    
# 从 file 文件里随机读取一行文本
def random_keywords(file = KEYWORDS_FILE):
    result = ""
    with open(file, 'r', encoding='utf-8') as file:
        # 读取所有行
        lines = file.readlines()
        random_line = random.choice(lines)
        result = random_line.strip()
    if result == "":
        result = "".join(random.choices(string.ascii_uppercase, k=5))
    return result
    
# 下划线转驼峰
def underscore_to_camelcase(underscore_string,lowerFirst = False):
    words = underscore_string.split('_')
    camelcase_string = ''.join(word.capitalize() for word in words)
    if lowerFirst == True:
        camelcase_string = camelcase_string[0].lower() + camelcase_string[1:]
    return camelcase_string
    
    
# 清空目录下的所有文件
def clear(directory):
    # 获取目录中的所有文件
    files = os.listdir(directory)
    # 遍历并删除每个文件
    for file in files:
        file_path = os.path.join(directory, file)
        if os.path.isfile(file_path):
            os.remove(file_path)


def main():
    
    if not os.path.exists(OUTPUT):
        os.makedirs(OUTPUT)
    clear(OUTPUT)
    
    # 一共生成多少个类
    total = FILE_NUM
    
    # 每个文件最多关联多少个类
    link = total if total < 20 else 20
    
    allObjcClass = []
    for i in range(0, total):
        obj = ObjcClass.Random()
        allObjcClass.append(obj)
        
    for obj in allObjcClass:
        obj.link = random.sample(allObjcClass, random.randint(0, link))
        
    for obj in allObjcClass:
        obj.export()
        
    code = ""
    for obj in allObjcClass:
        code = f"{code}#import \"{obj.name}.h\"\n"
    file = open(f"{OUTPUT}/{CLASS_PRE}Headers.h", "w")
    file.write(code)
    file.close()

if __name__ == "__main__":
    main()

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容