[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-6990":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":29,"readmeContent":30,"aiSummary":31,"trendingCount":16,"starSnapshotCount":16,"syncStatus":32,"lastSyncTime":33,"discoverSource":34},6990,"LifetimeTracker","krzysztofzablocki\u002FLifetimeTracker","krzysztofzablocki","Find retain cycles \u002F memory leaks sooner.","http:\u002F\u002Fmerowing.info",null,"Swift",3301,154,28,9,0,7,59.27,"MIT License",false,"master",true,[24,25,26,27,28],"ios","memory-leaks","retain-cycles","swift","tool","2026-06-12 04:00:31","# LifetimeTracker\n\n \n| ![Demo (bar)](Resources\u002Fdemo-bar.gif) | | ![Demo (circular)](Resources\u002Fdemo-circular.gif) |\n|:--:| :--: | :--: |\n| Bar style | | Circular style |\n\nLifetimeTracker can surface retain cycle \u002F memory issues right as you develop your application, and it will surface them to you immediately, so you can find them with more ease.\n\nInstruments and Memory Graph Debugger are great, but too many times, developers forget to check for issues as they close the feature implementation.\n\nIf you use those tools sporadically many of the issues they surface will require you to investigate the cause and cost you a lot of time in the process.\n\nOther tools like [FBRetainCycleDetector](https:\u002F\u002Fgithub.com\u002Ffacebook\u002FFBRetainCycleDetector) rely on objc runtime magic to find the problems, but that means they can't really be used for pure Swift classes. This small tool simply focuses on tracking lifetime of objects which means that it can be used in both Objective-C and Swift codebases, and it doesn't rely on any complex or automatic magic behaviour.\n\n[**If you'd like to support my work and improve your engineering workflows, check out my SwiftyStack course**](https:\u002F\u002Fwww.swiftystack.com\u002F)\n\n## Installation\n\n### CocoaPods\n\nAdd `pod 'LifetimeTracker'` to your Podfile.\n\n### Carthage\n\nAdd `github \"krzysztofzablocki\u002FLifetimeTracker\"` to your Cartfile.\n\n### Swift Package Manager\n\nAdd `LifetimeTracker\"` to the dependencies value of your Package.swift.\n\n```swift\ndependencies: [\n    .package(url: \"https:\u002F\u002Fgithub.com\u002Fkrzysztofzablocki\u002FLifetimeTracker.git\", .upToNextMajor(from: \"1.8.0\"))\n]\n```\n\n## Integration\n\nTo Integrate visual notifications simply add following line at the start of `AppDelegate(didFinishLaunchingWithOptions:)` or if you are using iOS 13+ SceneDelegates in `scene(willConnectTo:options:)`.\n\nSwift:\n\n```swift\n#if DEBUG\n\tLifetimeTracker.setup(\n        onUpdate: LifetimeTrackerDashboardIntegration(\n            visibility: .alwaysVisible,\n            style: .bar,\n            textColorForNoIssues: .systemGreen,\n            textColorForLeakDetected: .systemRed\n        ).refreshUI\n    )\n#endif\n```\n\nObjective-C:\n\n```objc\nLifetimeTrackerDashboardIntegration *dashboardIntegration = [LifetimeTrackerDashboardIntegration new];\n[dashboardIntegration setVisibleWhenIssueDetected];\n[dashboardIntegration useBarStyle];\n[LifetimeTracker setupOnUpdate:^(NSDictionary\u003CNSString *,EntriesGroup *> * groups) {\n    [dashboardIntegration refreshUIWithTrackedGroups: groups];\n}];\n```\n\nYou can control when the dashboard is visible: `alwaysVisible`, `alwaysHidden`, or `visibleWithIssuesDetected`.\n\nThere are two styles available. A overlay bar view which shows the detailed list of issues directly on the screen or a circular view which displays only the amount of issues and opens the detailed list as modal view controller.\n\n## Tracking key actors\n\nUsually, you want to use LifetimeTracker to track only key actors in your app, like ViewModels \u002F Controllers etc. When you have more than `maxCount` items alive, the tracker will let you know.\n\n### Swift\n\nYou conform to `LifetimeTrackable` and call `trackLifetime()` at the end of your init functions:\n\n```swift\nclass SectionFrontViewController: UIViewController, LifetimeTrackable {\n    class var lifetimeConfiguration: LifetimeConfiguration {\n        return LifetimeConfiguration(maxCount: 1, groupName: \"VC\")\n    }\n    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {\n        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)\n        \u002F\u002F\u002F ...\n        trackLifetime()\n    }\n}\n```\n\n### Objective-C\n\nYou conform to `LifetimeTrackable` and call `[self trackLifetime]` at the end of your init functions:\n\n```objc\n@import LifetimeTracker;\n\n@interface SectionFrontViewController() \u003CLifetimeTrackable>\n\n@implementation SectionFrontViewController\n\n+(LifetimeConfiguration *)lifetimeConfiguration\n{\n    return [[LifetimeConfiguration alloc] initWithMaxCount:1 groupName:@\"VC\"];\n}\n\n- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil\n{\n    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];\n    if (self) {\n    \t\u002F\u002F\u002F …\n        [self trackLifetime];\n    }\n    return self;\n}\n@end\n```\n\n## Integrating with [Danger](https:\u002F\u002Fdanger.systems)\n\nIf you are using Danger, you can use it to add both checkboxes to each PR to ensure people have verified no retain cycles were created but also to inform you when someone forgets to call `trackLifetime()` function.\n\n```ruby\n#\n# ** FILE CHECKS **\n# Checks for certain rules and warns if needed.\n# Some rules can be disabled by using \u002F\u002F danger:disable rule_name\n#\n# Rules:\n# - Check if the modified file is a View and doesn't implement LifetimeTrackable (lifetime_tracking)\n\n# Sometimes an added file is also counted as modified. We want the files to be checked only once.\nfiles_to_check = (git.modified_files + git.added_files).uniq\n(files_to_check - %w(Dangerfile)).each do |file|\n\tnext unless File.file?(file)\n\t# Only check inside swift files\n  next unless File.extname(file).include?(\".swift\")\n\n  # Will be used to check if we're inside a comment block.\n\tis_comment_block = false\n\n\t# Collects all disabled rules for this file.\n\tdisabled_rules = []\n\n\tfilelines = File.readlines(file)\n\tfilelines.each_with_index do |line, index|\n\t\tif is_comment_block\n\t\t\tif line.include?(\"*\u002F\")\n\t\t\t\tis_comment_block = false\n\t\t\tend\n\t\telsif line.include?(\"\u002F*\")\n\t\t\tis_comment_block = true\n\t\telsif line.include?(\"danger:disable\")\n\t\t\trule_to_disable = line.split.last\n\t\t\tdisabled_rules.push(rule_to_disable)\n\t\telse\n\t\t\t# Start our custom line checks\n\t\t\t# e.g. you could do something like check for methods that only call the super class' method\n\t\t\t#if line.include?(\"override\") and line.include?(\"func\") and filelines[index+1].include?(\"super\") and filelines[index+2].include?(\"}\")\n\t\t\t#\twarn(\"Override methods which only call super can be removed\", file: file, line: index+3)\n\t\t\t#end\n    end\n\tend\n\n\t# Only continue checks for Lifetime Trackable types\n\tnext unless (File.basename(file).include?(\"ViewModel\") or File.basename(file).include?(\"ViewController\") or File.basename(file).include?(\"View.swift\")) and !File.basename(file).include?(\"Node\") and !File.basename(file).include?(\"Tests\") and !File.basename(file).include?(\"FlowCoordinator\")\n\n\tif disabled_rules.include?(\"lifetime_tracking\") == false\n\t\tif File.readlines(file).grep(\u002FLifetimeTrackable\u002F).any?\n\t\t\tfail(\"You forgot to call trackLifetime() from your initializers in \" + File.basename(file, \".*\") + \" (lifetime_tracking)\") unless File.readlines(file).grep(\u002FtrackLifetime()\u002F).any?\n\t\telse\n\t\t\twarn(\"Please add support for LifetimeTrackable to \" + File.basename(file, \".*\") + \" . (lifetime_tracking)\")\n\t\tend\n\t\tmarkdown(\"- [ ] I've verified that showing and hiding \" + File.basename(file, \".*\") + \" doesn't surface any [LifetimeTracker](https:\u002F\u002Fgithub.com\u002Fkrzysztofzablocki\u002FLifetimeTracker) issues\")\n\tend\n\nend\n```\n\n## Surface last notification from the stack\n\nSometimes it is useful to get information about last retain cycle in order to log it to external sources such as analytics\u002Ftrackers. In order to do that we can update initial configuration with `onLeakDetected`:\n\n```objc\n[LifetimeTracker setupOnLeakDetected:^(Entry * entry, EntriesGroup * group) {\n    NSLog(@\"POSSIBLE LEAK ALERT: %@ - current count %li, max count %li\", entry.name, (long)entry.count, (long)entry.maxCount);\n} onUpdate:^(NSDictionary\u003CNSString *,EntriesGroup *> * groups) {\n    [dashboardIntegration refreshUIWithTrackedGroups: groups];\n}];\n```\n\n```swift\nLifetimeTracker.setup(onLeakDetected: { entity, _ in\n\tlog.warning(\"POSSIBLE LEAK ALERT: \\(entity.name) - current count: \\(entity.count), max count: \\(entity.maxCount)\")\n}, onUpdate: LifetimeTrackerDashboardIntegration(visibility: .alwaysVisible, style: .bar).refreshUI)\n```\n\n## Group tracked objects\n\nYou can group tracked objects together. `maxCount` of a group will be calculated by `maxCount` of all members per default. However, you can override it and provide a separate value to the group with `groupMaxCount`.\n\nYou may want to do this when you have a set of subclasses which can appear x times each, but in total only less than the sum of all subclasses:\n\n```swift\n\u002F\u002F DetailPage: UIViewController\n\n\u002F\u002F VideoDetailPage: DetailItem\nLifetimeConfiguration(maxCount: 3, groupName: \"Detail Page\")\n\n\u002F\u002F ImageDetailPage: DetailItem\nLifetimeConfiguration(maxCount: 3, groupName: \"Detail Page\")\n\n=> Group warning if 7 DetailPage objects are alive\n\n\u002F\u002F VideoDetailPage: DetailItem\nLifetimeConfiguration(maxCount: 3, groupName: \"Detail Page\", groupMaxCount: 3)\n\n\u002F\u002F ImageDetailPage: DetailItem\nLifetimeConfiguration(maxCount: 3, groupName: \"Detail Page\", groupMaxCount: 3)\n\n=> Group warning if 4 DetailPage object are alive\n\n```\n\n## Writing integration tests for memory leaks\n\nYou can access the summary label using accessibility identifier `LifetimeTracker.summaryLabel`, which allows you to write integration tests that end up with looking up whether any issues were found.\n\n## License\n\nLifetimeTracker is available under the MIT license. See [LICENSE](LICENSE) for more information.\n\n## Attributions\n\nI've used [SwiftPlate](https:\u002F\u002Fgithub.com\u002FJohnSundell\u002FSwiftPlate) to generate xcodeproj compatible with CocoaPods and Carthage.\n","LifetimeTracker 是一个用于在iOS应用开发过程中即时发现内存泄漏和保留循环问题的工具。其核心功能包括实时监控对象生命周期，并在出现问题时立即通知开发者，支持Swift和Objective-C代码库。与依赖于Objective-C运行时特性的其他工具不同，LifetimeTracker 通过直接跟踪对象的生命周期来工作，这使得它既适用于纯Swift项目也适用于混合语言环境。该工具特别适合于需要频繁检查并解决潜在内存问题的应用开发场景中使用，帮助开发者更早地识别并修复这些问题，从而提高应用性能和稳定性。",2,"2026-06-11 03:10:02","top_language"]