iOS懒加载(self.value与_value注意)

本文深入讲解iOS中的懒加载概念,包括其定义、实现方法及在代码中的应用技巧。阐述了如何通过重写getter方法实现对象的延迟加载,以减少内存占用,提高程序效率。

1、iOS懒加载定义

在iOS5之前需要使用编译器指令@synthesize告诉编译器帮助生成属性的getter,setter方法。之后会默认生成。编译器在生成getter,setter方法时先检查有没有自定义getter,setter方法,如果有则使用自定义的,没有定义系统就默认生成。
懒加载可以定义为:延时加载,即当对象需要用到的时候再去加载。其实就是重写属性的getter方法,然后加一个判断,为空则赋值,不为空则返回。
#import “testViewController.h”
@interface ViewController ()
@property (nonatomic, strong) UIView *testView;
@end
@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self. testView]; //注意:一定要是self.testView,如果是_testView子视图会为nil
    }
    // 懒加载
    -(UIView *) testView {
    if (_testView == nil) {
    _testView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 30)];
    _testView.backgroundColor = [UIColor redColor];
    }
    return _testView;
    }
    @end

2、iOS懒加载注意事项

1)、重写getter方法时,先判断对象当前是否为空,为空的话再去实例化对象;
2)、当使用self. testView会调用testView的getter方法而_ testView并不会调用,正确的使用个方式是通过self. testView去调用才会执行懒加载方法。

很多初学者在懒加载定义之外区域调用懒加载变量时,不怎么注意self. testView 和 _ testView的区别,一直使用_testView,所以才导致懒加载方法一直没有被调用。原因分析:self. testView会调用类的getter方法,而如果直接用_testView只是直接访问类的实例变量,而不会调用getter方法了。

3、iOS懒加载的优点

1)、对系统的内存占用率会减小;
2)、对象的实例化在getter方法中,各司其职,降低耦合性;
3)、不需将对象的实例化写到viewDidLoad,可以简化代码。

来源链接:https://www.jianshu.com/p/d2dc4d7d42c0

import queue import threading import xml.etree.ElementTree as ET import os from concurrent.futures.thread import ThreadPoolExecutor from openpyxl import Workbook import re from pathlib import Path from openpyxl.styles.builtins import title from collections import defaultdict import copy suffixes_android = ['strings.xml', 'strings_v6.xml', 'strings_v2.xml'] suffixes_ios = ['Localizable.strings', 'LocalizableAdded.strings'] title_path = set() queues_name_gloable = ['remediate_list', 'all_differ_key_value'] queues_name = {name: queue.Queue() for name in queues_name_gloable} ios_self_common = [] ios_self_tai = [] lock = threading.Lock() class xmlObj: def __init__(self, key, value, old_value, old_key, path, ios_key, ios_value, ios_path, languages): self.key = key self.xml_path = path self.value = value self.languages = languages self.ios_key = ios_key self.ios_value = ios_value self.ios_path = ios_path self.old_value = old_value self.old_key = old_key def __eq__(self, other): if isinstance(other, xmlObj): return (self.key == other.key and self.xml_path == other.xml_path and self.value == other.value and self.languages == other.languages and self.ios_key == other.ios_key and self.ios_value == other.ios_value and self.ios_path == other.ios_path and self.old_value == other.old_value and self.old_key == other.old_key) return False class iosObj: def __init__(self, key, value, path, androidKey, androidValue, androidPath, languages): self.key = key self.ios_path = path self.value = value self.androidKey = androidKey self.androidValue = androidValue self.androidPath = androidPath self.languages = languages def merge_xml_files(xml_files): try: title_path.add(xml_files.split("\\")[5]) tree = ET.parse(xml_files) root = tree.getroot() language_code = get_android_language(xml_files) android_list = [] for child in root.findall("string"): key = child.attrib.get("name") value = child.text android_list.append(xmlObj(key, value, '', '', xml_files, '', '', '', language_code)) return get_android_ios_obj(android_list) except ET.ParseError as e: print(f"Error parsing file {xml_files}: {e}") def get_android_language(xml_files): switch_dice = { "zh-rMO": "TW", "zh-rZH": "zh-rCN", "pt-rBR": "pt", "es-rLA": "es", "el-rGR": "el", "es-rES": "es" } direct_name = os.path.dirname(xml_files) # 获取目录路径 -> 'res/values-pt-rBR' # 使用正则表达式提取语言标识(如 'pt-rBR') match = re.search(r'values-([a-z]{2}(-[a-zA-Z0-9]{1,8})?)', direct_name) if match: language_code = match.group(1) # 输出: pt-rBR count = language_code.count('-') if count > 0: language_code = switch_dice.get(language_code, language_code) else: language_code = "en" # 默认值(如通用资源目录 values/) return language_code def get_ios_language(file_path): direct_name = os.path.dirname(file_path) language = os.path.basename(direct_name) count = language.count('-') if count == 0: language = language.split('.')[0] elif count == 1: language = language.split('.')[0].split('-')[0] elif count == 2: language = language.split('.')[0].split('-')[2] if language == "zh": language = "zh-rCN" elif language == "Base": language = "en" elif language == "CN": language = "TW" return language def parse_strings_files(ios_files): language = get_ios_language(ios_files) pattern = re.compile(r'"([^"]+)"\s*=\s*"([^"]*)";') with open(ios_files, 'r', encoding='utf-8', errors='ignore') as f: for line in f: match = pattern.match(line) if match: key = match.group(1) value = match.group(2) key = key.replace('\\', '"') value = value.replace('\\', '"') obj = iosObj(key, value, ios_files, '', '', '', language) if "Resource" in ios_files: ios_self_common.append(obj) else: ios_self_tai.append(obj) def travel_root(root_path): android_list = [] for root, dirs, files in os.walk(root_path, followlinks=False): path_android = [os.path.join(root, file) for file in files if file.endswith(tuple(suffixes_android))] [print(f"{file}") or parse_strings_files(os.path.join(root, file)) for file in files if file.endswith(tuple(suffixes_ios))] with ThreadPoolExecutor(max_workers=4) as executor: android_list = list(executor.map(merge_xml_files, path_android)) return android_list def get_android_ios_obj(android_list): queue_names = ['android_self_common', 'android_self_tai', 'android_list_self_common', 'android_list_self_tai', 'merge_xml_obj'] queues = {name: queue.Queue() for name in queue_names} for items_android in android_list: if "main" in items_android.xml_path: queues['android_self_common'].put(items_android) else: queues['android_self_tai'].put(items_android) if not queues['android_self_common'].empty(): queues['android_list_self_common'].put( compare_android_ios(list(queues['android_self_common'].queue), ios_self_common)) queues['android_list_self_tai'].put(compare_android_ios(list(queues['android_self_tai'].queue), ios_self_tai)) queues['merge_xml_obj'] = merge_list(queues['android_self_common'], queues['android_self_tai']) return queues['merge_xml_obj'] def merge_list(android_list_self_common, android_list_self_tai): with lock: merge_xml_obj = [] for _in in range(android_list_self_common.qsize()): merge_xml_obj.append(android_list_self_common.get()) for _in in range(android_list_self_tai.qsize()): merge_xml_obj.append(android_list_self_common.get()) return merge_xml_obj def is_same_language(android_value, ios_value): if android_value.languages == ios_value.languages: return True else: return False def get_all_differ(android_copy, ios_self): seen_keys = set() # 用于去重,确保每个 Android 仅添加一次 for self_ios in ios_self: for self_android in android_copy: for item in self_android: if self_ios.key != item.key and is_same_language(item, self_ios) and self_ios.value != item.value: key_and_value = str(item.key) + str(item.value) # 添加唯一标识避免重复 if key_and_value not in seen_keys: seen_keys.add(key_and_value) xml = xmlObj(item.key, item.value, item.value, item.key, item.xml_path, self_ios.key, self_ios.value, self_ios.ios_path, '') queues_name['all_differ_key_value'].put(xml) def compare_android_ios(android_self, ios_self): print("正在比较......") get_differ_key(android_self, ios_self) android_copy = copy.deepcopy(android_self) android = get_differ_value(android_copy, ios_self) return android def get_differ_key(android_self, ios_self): for self_android in android_self: for self_ios in ios_self: if self_android.value == self_ios.value and is_same_language(self_android, self_ios): if self_android.key != self_ios.key: old_key = self_android.key self_android.key = self_ios.key xml = xmlObj(self_android.key, self_android.value, self_android.value, old_key, self_android.xml_path, self_ios.key, self_ios.value, self_ios.ios_path, '') queues_name['remediate_list'].put(xml) def get_differ_value(android_copy, ios_self): for self_android in android_copy: for self_ios in ios_self: if self_android.key == self_ios.key and is_same_language(self_android, self_ios): if self_ios.value != self_android.value: self_android.value = self_ios.value xml = xmlObj(self_android.key, self_android.value, self_android.old_value, self_android.old_key, self_android.xml_path, self_ios.key, self_ios.value, self_ios.ios_path, '') queues_name['remediate_list'].put(xml) return copy.deepcopy(android_copy) def write_dict_to_xml(data_dict): print("写入xml") group_data = defaultdict(list) for obj in data_dict: for item in obj: group_data[item.xml_path].append(obj) for path, items in group_data.items(): resource = ET.Element('resources') for item in items: et = ET.SubElement( resource, "string", {"name": item.key} ) et.text = item.value tree = ET.ElementTree(resource) ET.indent(tree, space=" ") # 使 XML 格式整齐 tree.write(path, encoding="utf-8", xml_declaration=True, method='xml') print("写入文件") def write_to_excel(android_list_self, is_same): wb = Workbook() for item in list(android_list_self.queue): title = get_parent_directory(item.xml_path) for elem in title_path: if elem in item.xml_path: title = elem # 根据 title 获取或创建工作表 if title in wb.sheetnames: ws = wb[title] else: ws = wb.create_sheet(title=title) ws.append(["key", "value", "ios_key", "ios_value", "ios_path", "android_path", "old_value", "old_key"]) # 将数据追加到对应工作表 ws.append([item.key, item.value, item.ios_key, item.ios_value, item.ios_path, item.xml_path, item.old_value, item.old_key]) desktop_path = os.path.expanduser(r"D:\compare_excel") new_dir = os.path.join(desktop_path, 'android_save') os.makedirs(new_dir, exist_ok=True) if is_same: file_path = os.path.join(desktop_path, 'android_same.xlsx') else: file_path = os.path.join(desktop_path, 'android_not_same.xlsx') file_path = os.path.join(new_dir, file_path) wb.save(file_path) def get_parent_directory(xml_path): path = Path(xml_path) parts = path.parts for i in range(len(parts) - 1): if parts[i].lower() == 'res': return path.resolve().parts[i - 1] return None if __name__ == '__main__': android_map = {} android_root_path = r"C:\Users\f60039632\Desktop\android" ios_root_path = r"C:\Users\f60039632\Desktop\ios" travel_root(ios_root_path) key_value_list_android = travel_root(android_root_path) ios_self_common.extend(ios_self_tai) get_all_differ(key_value_list_android, ios_self_common) thread_remediate_list = threading.Thread(target=write_to_excel, args=(queues_name['remediate_list'], True)) thread_all_differ_key_value = threading.Thread(target=write_to_excel, args=(queues_name['all_differ_key_value'], False)) thread_remediate_list.start() thread_all_differ_key_value.start() write_dict_to_xml(key_value_list_android)
07-04
import queue import threading import xml.etree.ElementTree as ET import os from concurrent.futures.thread import ThreadPoolExecutor import re from pathlib import Path from collections import defaultdict import copy from pathlib import Path import openpyxl from openpyxl import Workbook import tkinter as tk from tkinter import ttk suffixes_android = ['strings.xml', 'strings_v6.xml', 'strings_v2.xml'] suffixes_ios = ['Localizable.strings', 'LocalizableAdded.strings'] title_path = set() all_differ_key_value = [] queues_name_gloable = ['remediate_list'] queues_name = {name: queue.Queue() for name in queues_name_gloable} # 创建布尔变量及选框 language_vars = {} # 公共资源 ios_self_common = [] # 定制资源 ios_self_tai = [] lock = threading.Lock() class xmlObj: def __init__(self, key, value, old_value, old_key, path, ios_key, ios_value, ios_path, languages): self.key = key self.xml_path = path self.value = value self.languages = languages self.ios_key = ios_key self.ios_value = ios_value self.ios_path = ios_path self.old_value = old_value self.old_key = old_key def __eq__(self, other): if isinstance(other, xmlObj): return (self.key == other.key and self.xml_path == other.xml_path and self.value == other.value and self.languages == other.languages and self.ios_key == other.ios_key and self.ios_value == other.ios_value and self.ios_path == other.ios_path and self.old_value == other.old_value and self.old_key == other.old_key) return False def __str__(self): attrs = [ f"Key: {self.key}", f"Value: {self.value}", f"Old Value: {self.old_value}", f"Old Key: {self.old_key}", f"XML Path: {self.xml_path}", f"iOS Key: {self.ios_key}", f"iOS Value: {self.ios_value}", f"iOS Path: {self.ios_path}", f"Languages: {self.languages}" ] return ', '.join(attrs) class iosObj: def __init__(self, key, value, path, androidKey, androidValue, androidPath, languages): self.key = key self.ios_path = path self.value = value self.androidKey = androidKey self.androidValue = androidValue self.androidPath = androidPath self.languages = languages def merge_xml_files(xml_files): try: title_path.add(xml_files.split("\\")[5]) tree = ET.parse(xml_files) root = tree.getroot() language_code = get_android_language(xml_files) android_list = [] for child in root.findall("string"): key = child.attrib.get("name") value = child.text android_list.append(xmlObj(key, value, '', '', xml_files, '', '', '', language_code)) return get_android_ios_obj(android_list) except ET.ParseError as e: print(f"Error parsing file {xml_files}: {e}") def get_android_language(xml_files): switch_dice = { "zh-rMO": "TW", "zh-rZH": "zh-rCN", "pt-rBR": "pt", "es-rLA": "es", "el-rGR": "el", "es-rES": "es", } direct_name = os.path.dirname(xml_files) # 获取目录路径 -> 'res/values-pt-rBR' # 使用正则表达式提取语言标识(如 'pt-rBR') match = re.search(r'values-([a-z]{2}(-[a-zA-Z0-9]{1,8})?)', direct_name) if match: language_code = match.group(1) # 输出: pt-rBR count = language_code.count('-') if count > 0: language_code = switch_dice.get(language_code, language_code) else: language_code = "en" return language_code def get_ios_language(file_path): direct_name = os.path.dirname(file_path) language = os.path.basename(direct_name) count = language.count('-') if count == 0: language = language.split('.')[0] elif count == 1: language = language.split('.')[0].split('-')[0] elif count == 2: language = language.split('.')[0].split('-')[2] if language == "zh": language = "zh-rCN" elif language == "Base": language = "en" elif language == "CN": language = "TW" return language def parse_strings_files(ios_files): language = get_ios_language(ios_files) pattern = re.compile(r'"([^"]+)"\s*=\s*"([^"]*)";') with open(ios_files, 'r', encoding='utf-8', errors='ignore') as f: for line in f: match = pattern.match(line) if match: key = match.group(1) value = match.group(2) key = key.replace('\\', '"') value = value.replace('\\', '"') obj = iosObj(key, value, ios_files, '', '', '', language) if "Resource" in ios_files: ios_self_common.append(obj) else: ios_self_tai.append(obj) ANDROID_FILE_PATTERN = re.compile(r'^strings(_v\d+)?\.xml$') def is_valid_android_file(file_name: str) -> bool: """判断文件是否为 Android 类型,并且不等于 menustrings.commonstrings,country_strings""" return (ANDROID_FILE_PATTERN.match(file_name) and file_name != "menustrings.xml" and file_name != "commonstrings.xml" and file_name != "country_strings.xml") def travel_root(root_path): android_list = [] path_android = [] try: for root, dirs, files in os.walk(root_path, followlinks=False): valid_android = [os.path.join(root, file) for file in files if is_valid_android_file(file) and "Build" not in os.path.abspath(os.path.join(root, file)) and file.endswith(tuple(suffixes_android)) and contains_language(os.path.join(root, file))] print(f"Directory: {root}, Android files: {valid_android}") path_android.extend(valid_android) [parse_strings_files(os.path.join(root, file)) for file in files if file.endswith(tuple(suffixes_ios))] print(f"Total Android files collected: {len(path_android)}") with ThreadPoolExecutor(max_workers=12) as executor: android_sublist = list(executor.map(merge_xml_files, path_android)) android_list.extend(android_sublist) except Exception as e: print(f"Error: {e}") return android_list def contains_language(path): for key, value in language_vars.items(): if value.get() and key in path: return True return False def get_android_ios_obj(android_list): android_self_common = [] android_self_tai = [] for items_android in android_list: if "main" in items_android.xml_path: android_self_common.append(items_android) else: android_self_tai.append(items_android) merge_xml_obj = merge_list(compare_android_ios(android_self_common, ios_self_common), compare_android_ios(android_self_tai, ios_self_tai)) return merge_xml_obj def merge_list(android_list_self_common, android_list_self_tai): with lock: merge_xml_obj = [] merge_xml_obj.extend(android_list_self_common + android_list_self_tai) return merge_xml_obj def is_same_language(android_value, ios_value): if android_value.languages == ios_value.languages: return True else: return False def get_all_differ(android_copy, ios_self): try: android_by_key_and_value = defaultdict(list) ios_by_key_and_value = defaultdict(list) flatten_list = [item for sublist in android_copy for item in sublist] for item in flatten_list: if hasattr(item, "key") and hasattr(item, "value"): key = f"{item.key}{item.value}" android_by_key_and_value[key] = item else: print(f"无效对象,不包含 key 或 value 属性: {item}") for item in ios_self: if hasattr(item, "key") and hasattr(item, "value"): key = f"{item.key}{item.value}" ios_by_key_and_value[key] = item else: print(f"无效对象,不包含 key 或 value 属性: {item}") for key in android_by_key_and_value: if key not in ios_by_key_and_value: item = android_by_key_and_value.get(key, 'default') if item != 'default': all_differ_key_value.append(item) except Exception as e: print(f"get_all_differ函数执行出错: {e}") def compare_android_ios(android_self, ios_self): print("正在比较......") get_differ_key(android_self, ios_self) android_copy = copy.deepcopy(android_self) return get_differ_value(android_copy, ios_self) def get_differ_key(android_self, ios_self): try: for self_android in android_self: for self_ios in ios_self: if self_android.value == self_ios.value and is_same_language(self_android, self_ios): if self_android.key != self_ios.key: old_key = self_android.key self_android.key = self_ios.key xml = xmlObj(self_android.key, self_android.value, self_android.value, old_key, self_android.xml_path, self_ios.key, self_ios.value, self_ios.ios_path, '') queues_name['remediate_list'].put(xml) except Exception as e: print(f"get_differ_key 报错:{e}") def get_differ_value(android_copy, ios_self): for self_android in android_copy: for self_ios in ios_self: if self_android.key == self_ios.key and is_same_language(self_android, self_ios): if self_ios.value != self_android.value: self_android.value = self_ios.value xml = xmlObj(self_android.key, self_android.value, self_android.old_value, self_android.old_key, self_android.xml_path, self_ios.key, self_ios.value, self_ios.ios_path, '') queues_name['remediate_list'].put(xml) return copy.deepcopy(android_copy) def write_dict_to_xml(data_dict): try: group_data = defaultdict(list) for obj in data_dict: for item in obj: group_data[item.xml_path].append(item) for path, items in group_data.items(): resource = ET.Element('resources') for item in items: et = ET.SubElement( resource, "string", {"name": item.key} ) et.text = item.value tree = ET.ElementTree(resource) ET.indent(tree, space=" ") # 使 XML 格式整齐 tree.write(path, encoding="utf-8", xml_declaration=True, method='xml') print(f"写入文件中{path}请稍等") except IOError as e: print(f"写入xml文件操作失败({path}): {str(e)}") except AttributeError as e: print(f"写入xml对象属性缺失: {str(e)}") except ET.ParseError as e: print(f"写入XML格式错误: {str(e)}") except Exception as e: print(f"写入xml未知错误: {str(e)}") def write_to_excel(android_list_self, is_same, path): try: print("正在写入excel") wb = Workbook() for item in android_list_self: title = get_parent_directory(item.xml_path) for elem in title_path: if elem in item.xml_path: title = elem # 根据 title 获取或创建工作表 if title in wb.sheetnames: ws = wb[title] else: ws = wb.create_sheet(title=title) if is_same: ws.append( ["old_key", "old_value", "ios_key", "ios_value", "ios_path", "android_path", "key", "value"]) else: ws.append( ["old_key", "old_value", "ios_key", "ios_value", "ios_path", "android_path", "key", "value"]) # 将数据追加到对应工作表 ws.append( [item.old_key, item.old_value, item.ios_key, item.ios_value, item.ios_path, item.xml_path, item.key, item.value]) if is_same: file_path = os.path.join(path, 'android_same.xlsx') else: file_path = os.path.join(path, 'android_not_same.xlsx') file_path = os.path.join(path, file_path) wb.save(file_path) except PermissionError as e: print(f"文件保存失败:权限不足 ({str(e)})") except FileNotFoundError as e: print(f"文件路径无效:路径不存在 ({str(e)})") except openpyxl.utils.exceptions.IllegalCharacterError as e: print(f"Excel文件数据异常:包含非法字符 ({str(e)})") except AttributeError as e: print(f"对象属性错误:请检查数据完整性 ({str(e)})") def get_parent_directory(xml_path): path = Path(xml_path) parts = path.parts for i in range(len(parts) - 1): if parts[i].lower() == 'res': return path.resolve().parts[i - 1] return None is_all_selected = False def on_submit(): selected = [lang for lang, var in language_vars.items() if var.get()] print(f"你选择了: {selected}") root.destroy() def toggle_all(): global is_all_selected is_all_selected = not is_all_selected for var in language_vars.values(): var.set(is_all_selected) # 初始化窗口 root = tk.Tk() root.title("语言选择") root.geometry("400x800") # 语言选项(使用语言代码) languages = ['ar', 'ca', 'de', 'el', 'en', 'enm', 'es-rES', 'es-rLA', 'eu', 'fr', 'pt-rBR', 'ru', 'th', 'zh-rCN', 'zh-rMO', 'zh-rZH'] # 全选按钮 ttk.Button(root, text="全选", command=toggle_all).grid(row=len(languages) + 1, column=0, padx=20, pady=20) # 提交按钮 ttk.Button(root, text="提交", command=on_submit).grid(row=len(languages) + 1, column=1, padx=20, pady=20) # 复选框按钮 for idx, lang in enumerate(languages): var = tk.BooleanVar() ttk.Checkbutton(root, text=lang, variable=var).grid(row=idx, sticky="ew", padx=10, pady=5) language_vars[lang] = var # 启动事件循环 root.mainloop() if __name__ == '__main__': android_map = {} android_root_path = input("请输入Android路径:") ios_root_path = input("请输入ios路径:") travel_root(ios_root_path) key_value_list_android = travel_root(android_root_path) ios_self_common.extend(ios_self_tai) get_all_differ(key_value_list_android, ios_self_common) data_dict = list(queues_name['remediate_list'].queue) thread_remediate_list = threading.Thread(target=write_to_excel, args=(data_dict, True, android_root_path)) thread_all_differ_key_value = threading.Thread(target=write_to_excel, args=(all_differ_key_value, False, android_root_path)) thread_remediate_list.start() thread_all_differ_key_value.start() write_dict_to_xml(key_value_list_android)
最新发布
07-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值