├── MLeaksFinder.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── Podfile.lock
├── MLeaksFinder.xcworkspace
└── contents.xcworkspacedata
├── Podfile
├── FAQ-CN.md
├── MLeaksFinder
├── UITouch+MemoryLeak.h
├── UIView+MemoryLeak.h
├── UIApplication+MemoryLeak.h
├── UIViewController+MemoryLeak.h
├── UIPageViewController+MemoryLeak.h
├── UITabBarController+MemoryLeak.h
├── UINavigationController+MemoryLeak.h
├── UISplitViewController+MemoryLeak.h
├── MLeakedObjectProxy.h
├── UIView+MemoryLeak.m
├── MLeaksMessenger.h
├── UITabBarController+MemoryLeak.m
├── UIPageViewController+MemoryLeak.m
├── UISplitViewController+MemoryLeak.m
├── MLeaksFinder.h
├── NSObject+MemoryLeak.h
├── UITouch+MemoryLeak.m
├── UIApplication+MemoryLeak.m
├── MLeaksMessenger.m
├── UIViewController+MemoryLeak.m
├── UINavigationController+MemoryLeak.m
├── MLeakedObjectProxy.m
└── NSObject+MemoryLeak.m
├── .gitignore
├── MLeaksFinder.podspec
├── LICENSE.TXT
└── README.md
/MLeaksFinder.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - FBRetainCycleDetector (0.1.2)
3 |
4 | DEPENDENCIES:
5 | - FBRetainCycleDetector
6 |
7 | SPEC CHECKSUMS:
8 | FBRetainCycleDetector: 45462f9ed1af0cd77224a4cc4e6dacaca47371b4
9 |
10 | PODFILE CHECKSUM: 38741d1572d2c8740a441bc6562c61fa2ce1ef2e
11 |
12 | COCOAPODS: 1.0.0
13 |
--------------------------------------------------------------------------------
/MLeaksFinder.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | platform :ios, '7.0'
3 |
4 | target 'MLeaksFinder' do
5 | # Uncomment this line if you're using Swift or would like to use dynamic frameworks
6 | # use_frameworks!
7 |
8 | # Pods for MLeaksFinder
9 | pod 'FBRetainCycleDetector'
10 |
11 | end
12 |
--------------------------------------------------------------------------------
/FAQ-CN.md:
--------------------------------------------------------------------------------
1 | # FAQ
2 | **1) 引进 MLeaksFinder 后没生效?**
3 |
4 | * 先验证引进是否正确,在 UIViewController+MemoryLeak.m 的 `+ (void)load` 方法里加断点,app 启动时进入该方法则引进成功,否则引进失败。
5 | * 用 CocoaPods 安装时注意有没有 warnings,特别是 `OTHER_LDFLAGS` 相关的 warnings。如果有 warnings,可以在主工程的 Build Settings -> Other Linker Flags 加上 `-ObjC`。
6 |
7 | **2) 可以手动引进 MLeaksFinder 吗?**
8 |
9 | * 直接把 MLeaksFinder 的代码放到项目里即生效。如果把 MLeaksFinder 做为子工程,需要在主工程的 Build Settings -> Other Linker Flags 加上 `-ObjC`。
10 | * 引进 MLeaksFinder 的代码后即可检测内存泄漏,但查找循环引用的功能还未生效。可以再手动加入 FBRetainCycleDetector 代码,然后把 MLeaksFinder.h 里的 `//#define MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED 1` 打开。
11 |
12 | **3) Fail to find a retain cycle?**
13 |
14 | * 内存泄漏不一定是循环引用造成的。
15 | * 有的循环引用 FBRetainCycleDetector 不一定能找出。
16 |
17 | **4) 如何关掉 MLeaksFinder?**
18 |
19 | * MLeaksFinder 默认只在 debug 下生效,当然也可以通过 MLeaksFinder.h 里的 `//#define MEMORY_LEAKS_FINDER_ENABLED 0` 来手动控制开关。
20 |
--------------------------------------------------------------------------------
/MLeaksFinder/UITouch+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UITouch (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIView+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UIView (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIApplication+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UIApplication (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIViewController+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UIViewController (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIPageViewController+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UIPageViewController (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/UITabBarController+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UITabBarController (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/UINavigationController+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UINavigationController (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/UISplitViewController+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import "MLeaksFinder.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @interface UISplitViewController (MemoryLeak)
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/MLeaksFinder/MLeakedObjectProxy.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 |
15 | @interface MLeakedObjectProxy : NSObject
16 |
17 | + (BOOL)isAnyObjectLeakedAtPtrs:(NSSet *)ptrs;
18 | + (void)addLeakedObject:(id)object;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIView+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UIView+MemoryLeak.h"
14 | #import "NSObject+MemoryLeak.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @implementation UIView (MemoryLeak)
19 |
20 | - (BOOL)willDealloc {
21 | if (![super willDealloc]) {
22 | return NO;
23 | }
24 |
25 | [self willReleaseChildren:self.subviews];
26 |
27 | return YES;
28 | }
29 |
30 | @end
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/MLeaksFinder/MLeaksMessenger.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 | #import
15 |
16 | @interface MLeaksMessenger : NSObject
17 |
18 | + (void)alertWithTitle:(NSString *)title message:(NSString *)message;
19 | + (void)alertWithTitle:(NSString *)title
20 | message:(NSString *)message
21 | delegate:(id)delegate
22 | additionalButtonTitle:(NSString *)additionalButtonTitle;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/MLeaksFinder/UITabBarController+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UITabBarController+MemoryLeak.h"
14 | #import "NSObject+MemoryLeak.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @implementation UITabBarController (MemoryLeak)
19 |
20 | - (BOOL)willDealloc {
21 | if (![super willDealloc]) {
22 | return NO;
23 | }
24 |
25 | [self willReleaseChildren:self.viewControllers];
26 |
27 | return YES;
28 | }
29 |
30 | @end
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIPageViewController+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UIPageViewController+MemoryLeak.h"
14 | #import "NSObject+MemoryLeak.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @implementation UIPageViewController (MemoryLeak)
19 |
20 | - (BOOL)willDealloc {
21 | if (![super willDealloc]) {
22 | return NO;
23 | }
24 |
25 | [self willReleaseChildren:self.viewControllers];
26 |
27 | return YES;
28 | }
29 |
30 | @end
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/MLeaksFinder/UISplitViewController+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UISplitViewController+MemoryLeak.h"
14 | #import "NSObject+MemoryLeak.h"
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | @implementation UISplitViewController (MemoryLeak)
19 |
20 | - (BOOL)willDealloc {
21 | if (![super willDealloc]) {
22 | return NO;
23 | }
24 |
25 | [self willReleaseChildren:self.viewControllers];
26 |
27 | return YES;
28 | }
29 |
30 | @end
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/MLeaksFinder/MLeaksFinder.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "NSObject+MemoryLeak.h"
14 |
15 | //#define MEMORY_LEAKS_FINDER_ENABLED 0
16 |
17 | #ifdef MEMORY_LEAKS_FINDER_ENABLED
18 | #define _INTERNAL_MLF_ENABLED MEMORY_LEAKS_FINDER_ENABLED
19 | #else
20 | #define _INTERNAL_MLF_ENABLED DEBUG
21 | #endif
22 |
23 | #define MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED 0
24 |
25 | #ifdef MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED
26 | #define _INTERNAL_MLF_RC_ENABLED MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED
27 | #elif COCOAPODS
28 | #define _INTERNAL_MLF_RC_ENABLED COCOAPODS
29 | #endif
30 |
--------------------------------------------------------------------------------
/MLeaksFinder/NSObject+MemoryLeak.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import
14 |
15 | #define MLCheck(TARGET) [self willReleaseObject:(TARGET) relationship:@#TARGET];
16 |
17 | @protocol MLeaksFinderDelegate
18 |
19 | - (BOOL)viewController:(UIViewController *)viewController shouldCheckProperty:(NSString *)propertyName;
20 |
21 | @end
22 |
23 | @interface NSObject (MemoryLeak)
24 |
25 | - (BOOL)willDealloc;
26 | - (void)willReleaseObject:(id)object relationship:(NSString *)relationship;
27 |
28 | - (void)willReleaseChild:(id)child;
29 | - (void)willReleaseChildren:(NSArray *)children;
30 |
31 | - (NSArray *)viewStack;
32 |
33 | + (void)setDelegate:(id)delegate;
34 |
35 | + (void)addClassNamesToWhitelist:(NSArray *)classNames;
36 |
37 | + (void)swizzleSEL:(SEL)originalSEL withSEL:(SEL)swizzledSEL;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/MLeaksFinder/UITouch+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UITouch+MemoryLeak.h"
14 | #import
15 |
16 | #if _INTERNAL_MLF_ENABLED
17 |
18 | extern const void *const kLatestSenderKey;
19 |
20 | @implementation UITouch (MemoryLeak)
21 |
22 | + (void)load {
23 | static dispatch_once_t onceToken;
24 | dispatch_once(&onceToken, ^{
25 | [self swizzleSEL:@selector(setView:) withSEL:@selector(swizzled_setView:)];
26 | });
27 | }
28 |
29 | - (void)swizzled_setView:(UIView *)view {
30 | [self swizzled_setView:view];
31 |
32 | if (view) {
33 | objc_setAssociatedObject([UIApplication sharedApplication],
34 | kLatestSenderKey,
35 | @((uintptr_t)view),
36 | OBJC_ASSOCIATION_RETAIN);
37 | }
38 | }
39 |
40 | @end
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | # CocoaPods
31 | #
32 | # We recommend against adding the Pods directory to your .gitignore. However
33 | # you should judge for yourself, the pros and cons are mentioned at:
34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35 | #
36 | Pods/
37 |
38 | # Carthage
39 | #
40 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
41 | # Carthage/Checkouts
42 |
43 | Carthage/Build
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
51 |
52 | fastlane/report.xml
53 | fastlane/screenshots
54 |
55 | # Code Injection
56 | #
57 | # After new code Injection tools there's a generated folder /iOSInjectionProject
58 | # https://github.com/johnno1962/injectionforxcode
59 |
60 | iOSInjectionProject/
61 |
62 | .DS_Store
63 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIApplication+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UIApplication+MemoryLeak.h"
14 | #import "NSObject+MemoryLeak.h"
15 | #import
16 |
17 | #if _INTERNAL_MLF_ENABLED
18 |
19 | extern const void *const kLatestSenderKey;
20 |
21 | @implementation UIApplication (MemoryLeak)
22 |
23 | + (void)load {
24 | static dispatch_once_t onceToken;
25 | dispatch_once(&onceToken, ^{
26 | [self swizzleSEL:@selector(sendAction:to:from:forEvent:) withSEL:@selector(swizzled_sendAction:to:from:forEvent:)];
27 | });
28 | }
29 |
30 | - (BOOL)swizzled_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event {
31 | objc_setAssociatedObject(self, kLatestSenderKey, @((uintptr_t)sender), OBJC_ASSOCIATION_RETAIN);
32 |
33 | return [self swizzled_sendAction:action to:target from:sender forEvent:event];
34 | }
35 |
36 | @end
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/MLeaksFinder.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod lib lint MLeaksFinder.podspec' to ensure this is a
3 | # valid spec before submitting.
4 | #
5 | # Any lines starting with a # are optional, but their use is encouraged
6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
7 | #
8 |
9 | Pod::Spec.new do |s|
10 | s.name = "MLeaksFinder"
11 | s.version = "1.0.0"
12 | s.summary = "Find memory leaks in your iOS app at develop time."
13 |
14 | # This description is used to generate tags and improve search results.
15 | # * Think: What does it do? Why did you write it? What is the focus?
16 | # * Try to keep it short, snappy and to the point.
17 | # * Write the description between the DESC delimiters below.
18 | # * Finally, don't worry about the indent, CocoaPods strips it!
19 |
20 | # s.description = <<-DESC
21 | #TODO: Add long description of the pod here.
22 | # DESC
23 |
24 | s.homepage = "https://github.com/Zepo/MLeaksFinder"
25 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
26 | s.license = 'MIT'
27 | s.author = { "Zeposhe" => "zeposhe@163.com" }
28 | s.source = { :git => "https://github.com/Zepo/MLeaksFinder.git", :tag => s.version }
29 | # s.social_media_url = 'https://twitter.com/'
30 |
31 | s.ios.deployment_target = '6.0'
32 |
33 | s.source_files = 'MLeaksFinder/**/*'
34 |
35 | # s.resource_bundles = {
36 | # 'MLeaksFinder' => ['MLeaksFinder/Assets/*.png']
37 | # }
38 |
39 | s.public_header_files = 'MLeaksFinder/MLeaksFinder.h', 'MLeaksFinder/NSObject+MemoryLeak.h'
40 | # s.frameworks = 'UIKit', 'MapKit'
41 | # s.dependency 'FBRetainCycleDetector'
42 | end
43 |
--------------------------------------------------------------------------------
/MLeaksFinder/MLeaksMessenger.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "MLeaksMessenger.h"
14 |
15 | static __weak UIAlertView *alertView;
16 |
17 | @implementation MLeaksMessenger
18 |
19 | + (void)alertWithTitle:(NSString *)title message:(NSString *)message {
20 | [self alertWithTitle:title message:message delegate:nil additionalButtonTitle:nil];
21 | }
22 |
23 | + (void)alertWithTitle:(NSString *)title
24 | message:(NSString *)message
25 | delegate:(id)delegate
26 | additionalButtonTitle:(NSString *)additionalButtonTitle {
27 | [alertView dismissWithClickedButtonIndex:0 animated:NO];
28 | UIAlertView *alertViewTemp = [[UIAlertView alloc] initWithTitle:title
29 | message:message
30 | delegate:delegate
31 | cancelButtonTitle:@"OK"
32 | otherButtonTitles:additionalButtonTitle, nil];
33 | [alertViewTemp show];
34 | alertView = alertViewTemp;
35 |
36 | NSLog(@"%@: %@", title, message);
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | Tencent is pleased to support the open source community by making MLeaksFinder available.
2 | Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
3 | If you have downloaded a copy of the MLeaksFinder binary from Tencent, please note that the MLeaksFinder binary is licensed under the BSD 3-Clause License.
4 | If you have downloaded a copy of the MLeaksFinder source code from Tencent, please note that MLeaksFinder source code is licensed under the BSD 3-Clause License. Your integration of MLeaksFinder into your own projects may require compliance with the BSD 3-Clause License.
5 | A copy of the BSD 3-Clause License is included in this file.
6 |
7 |
8 |
9 | Terms of the BSD 3-Clause License:
10 | --------------------------------------------------------------------
11 |
12 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
13 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
14 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
15 | Neither the name of [copyright holder] nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [中文介绍](http://wereadteam.github.io/2016/07/20/MLeaksFinder2/) | [FAQ中文](https://github.com/Zepo/MLeaksFinder/blob/master/FAQ-CN.md)
2 |
3 | # MLeaksFinder
4 | MLeaksFinder helps you find memory leaks in your iOS apps at develop time. It can automatically find leaks in UIView and UIViewController objects, present an alert with the leaked object in its View-ViewController stack when leaks happening. ~~More over, it can try to find a retain cycle for the leaked object using [FBRetainCycleDetector](https://github.com/facebook/FBRetainCycleDetector/tree/master/FBRetainCycleDetector).~~ Besides finding leaks in UIView and UIViewController objects, developers can extend it to find leaks in other kinds of objects.
5 |
6 | # Communication
7 | QQ group: 482121244
8 |
9 | # Installation
10 | ```
11 | pod 'MLeaksFinder'
12 | ```
13 | MLeaksFinder comes into effect after `pod install`, there is no need to add any code nor to import any header file.
14 |
15 | *WARNING: FBRetainCycleDetector is removed from the podspec due to Facebook's BSD-plus-Patents license. If you want to use FBRetainCycleDetector to find retain cycle, add `pod 'FBRetainCycleDetector'` to your project's Podfile and turn the macro `MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED` on in `MLeaksFinder.h`.*
16 |
17 | # Usage
18 | MLeaksFinder can automatically find leaks in UIView and UIViewController objects. When leaks happening, it will present an alert with the leaked object in its View-ViewController stack.
19 | ```
20 | Memory Leak
21 | (
22 | MyTableViewController,
23 | UITableView,
24 | UITableViewWrapperView,
25 | MyTableViewCell
26 | )
27 | ```
28 |
29 | For the above example, we are sure that objects of `MyTableViewController`, `UITableView`, `UITableViewWrapperView` are deallocated successfully, but not the objects of `MyTableViewCell`.
30 |
31 | ## Mute Assertion
32 | If your class is designed as singleton or for some reason objects of your class should not be dealloced, override `- (BOOL)willDealloc` in your class by returning NO.
33 | ```objc
34 | - (BOOL)willDealloc {
35 | return NO;
36 | }
37 | ```
38 |
39 | ## Find Leaks in Other Objects
40 | MLeaksFinder finds leaks in UIView and UIViewController objects by default. However, you can extend it to find leaks in the whole object graph rooted at a UIViewController object.
41 | ```objc
42 | - (BOOL)willDealloc {
43 | if (![super willDealloc]) {
44 | return NO;
45 | }
46 |
47 | MLCheck(self.viewModel);
48 | return YES;
49 | }
50 | ```
51 |
--------------------------------------------------------------------------------
/MLeaksFinder/UIViewController+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UIViewController+MemoryLeak.h"
14 | #import "NSObject+MemoryLeak.h"
15 | #import
16 |
17 | #if _INTERNAL_MLF_ENABLED
18 |
19 | const void *const kHasBeenPoppedKey = &kHasBeenPoppedKey;
20 | extern const void *const kDelegateKey;
21 |
22 | @implementation UIViewController (MemoryLeak)
23 |
24 | + (void)load {
25 | static dispatch_once_t onceToken;
26 | dispatch_once(&onceToken, ^{
27 | [self swizzleSEL:@selector(viewDidDisappear:) withSEL:@selector(swizzled_viewDidDisappear:)];
28 | [self swizzleSEL:@selector(viewWillAppear:) withSEL:@selector(swizzled_viewWillAppear:)];
29 | [self swizzleSEL:@selector(dismissViewControllerAnimated:completion:) withSEL:@selector(swizzled_dismissViewControllerAnimated:completion:)];
30 | });
31 | }
32 |
33 | - (void)swizzled_viewDidDisappear:(BOOL)animated {
34 | [self swizzled_viewDidDisappear:animated];
35 |
36 | if ([objc_getAssociatedObject(self, kHasBeenPoppedKey) boolValue]) {
37 | [self willDealloc];
38 | }
39 | }
40 |
41 | - (void)swizzled_viewWillAppear:(BOOL)animated {
42 | [self swizzled_viewWillAppear:animated];
43 |
44 | objc_setAssociatedObject(self, kHasBeenPoppedKey, @(NO), OBJC_ASSOCIATION_RETAIN);
45 | }
46 |
47 | - (void)swizzled_dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
48 | [self swizzled_dismissViewControllerAnimated:flag completion:completion];
49 |
50 | UIViewController *dismissedViewController = self.presentedViewController;
51 | if (!dismissedViewController && self.presentingViewController) {
52 | dismissedViewController = self;
53 | }
54 |
55 | if (!dismissedViewController) return;
56 |
57 | [dismissedViewController willDealloc];
58 | }
59 |
60 | - (BOOL)willDealloc {
61 | if (![super willDealloc]) {
62 | return NO;
63 | }
64 |
65 | [self willReleaseChildren:self.childViewControllers];
66 | [self willReleaseChild:self.presentedViewController];
67 |
68 | if (self.isViewLoaded) {
69 | [self willReleaseChild:self.view];
70 | }
71 |
72 | unsigned int count;
73 | Ivar *ivars = class_copyIvarList([self class], &count);
74 | for (unsigned int i = 0; i < count; ++i) {
75 | Ivar ivar = ivars[i];
76 | NSString *ivarName = @(ivar_getName(ivar));
77 | NSString *ivarType = @(ivar_getTypeEncoding(ivar));
78 | if (![ivarType hasPrefix:@"@"]) {
79 | continue;
80 | }
81 | id delegate = objc_getAssociatedObject([NSObject class], kDelegateKey);
82 | if (delegate && [delegate viewController:self shouldCheckProperty:ivarName]) {
83 | id ivarObject = object_getIvar(self, ivar);
84 | if (ivarObject) {
85 | [self willReleaseChild:ivarObject];
86 | }
87 | }
88 | }
89 | free(ivars);
90 |
91 | return YES;
92 | }
93 |
94 | @end
95 |
96 | #endif
97 |
--------------------------------------------------------------------------------
/MLeaksFinder/UINavigationController+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "UINavigationController+MemoryLeak.h"
14 | #import "NSObject+MemoryLeak.h"
15 | #import
16 |
17 | #if _INTERNAL_MLF_ENABLED
18 |
19 | static const void *const kPoppedDetailVCKey = &kPoppedDetailVCKey;
20 |
21 | @implementation UINavigationController (MemoryLeak)
22 |
23 | + (void)load {
24 | static dispatch_once_t onceToken;
25 | dispatch_once(&onceToken, ^{
26 | [self swizzleSEL:@selector(pushViewController:animated:) withSEL:@selector(swizzled_pushViewController:animated:)];
27 | [self swizzleSEL:@selector(popViewControllerAnimated:) withSEL:@selector(swizzled_popViewControllerAnimated:)];
28 | [self swizzleSEL:@selector(popToViewController:animated:) withSEL:@selector(swizzled_popToViewController:animated:)];
29 | [self swizzleSEL:@selector(popToRootViewControllerAnimated:) withSEL:@selector(swizzled_popToRootViewControllerAnimated:)];
30 | });
31 | }
32 |
33 | - (void)swizzled_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
34 | if (self.splitViewController) {
35 | id detailViewController = objc_getAssociatedObject(self, kPoppedDetailVCKey);
36 | if ([detailViewController isKindOfClass:[UIViewController class]]) {
37 | [detailViewController willDealloc];
38 | objc_setAssociatedObject(self, kPoppedDetailVCKey, nil, OBJC_ASSOCIATION_RETAIN);
39 | }
40 | }
41 |
42 | [self swizzled_pushViewController:viewController animated:animated];
43 | }
44 |
45 | - (UIViewController *)swizzled_popViewControllerAnimated:(BOOL)animated {
46 | UIViewController *poppedViewController = [self swizzled_popViewControllerAnimated:animated];
47 |
48 | if (!poppedViewController) {
49 | return nil;
50 | }
51 |
52 | // Detail VC in UISplitViewController is not dealloced until another detail VC is shown
53 | if (self.splitViewController &&
54 | self.splitViewController.viewControllers.firstObject == self &&
55 | self.splitViewController == poppedViewController.splitViewController) {
56 | objc_setAssociatedObject(self, kPoppedDetailVCKey, poppedViewController, OBJC_ASSOCIATION_RETAIN);
57 | return poppedViewController;
58 | }
59 |
60 | // VC is not dealloced until disappear when popped using a left-edge swipe gesture
61 | extern const void *const kHasBeenPoppedKey;
62 | objc_setAssociatedObject(poppedViewController, kHasBeenPoppedKey, @(YES), OBJC_ASSOCIATION_RETAIN);
63 |
64 | return poppedViewController;
65 | }
66 |
67 | - (NSArray *)swizzled_popToViewController:(UIViewController *)viewController animated:(BOOL)animated {
68 | NSArray *poppedViewControllers = [self swizzled_popToViewController:viewController animated:animated];
69 |
70 | for (UIViewController *viewController in poppedViewControllers) {
71 | [viewController willDealloc];
72 | }
73 |
74 | return poppedViewControllers;
75 | }
76 |
77 | - (NSArray *)swizzled_popToRootViewControllerAnimated:(BOOL)animated {
78 | NSArray *poppedViewControllers = [self swizzled_popToRootViewControllerAnimated:animated];
79 |
80 | for (UIViewController *viewController in poppedViewControllers) {
81 | [viewController willDealloc];
82 | }
83 |
84 | return poppedViewControllers;
85 | }
86 |
87 | - (BOOL)willDealloc {
88 | if (![super willDealloc]) {
89 | return NO;
90 | }
91 |
92 | [self willReleaseChildren:self.viewControllers];
93 |
94 | return YES;
95 | }
96 |
97 | @end
98 |
99 | #endif
100 |
--------------------------------------------------------------------------------
/MLeaksFinder/MLeakedObjectProxy.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "MLeakedObjectProxy.h"
14 | #import "MLeaksFinder.h"
15 | #import "MLeaksMessenger.h"
16 | #import "NSObject+MemoryLeak.h"
17 | #import
18 | #import
19 |
20 | #if _INTERNAL_MLF_RC_ENABLED
21 | #import
22 | #endif
23 |
24 | static NSMutableSet *leakedObjectPtrs;
25 |
26 | @interface MLeakedObjectProxy ()
27 | @property (nonatomic, weak) id object;
28 | @property (nonatomic, strong) NSNumber *objectPtr;
29 | @property (nonatomic, strong) NSArray *viewStack;
30 | @end
31 |
32 | @implementation MLeakedObjectProxy
33 |
34 | + (BOOL)isAnyObjectLeakedAtPtrs:(NSSet *)ptrs {
35 | NSAssert([NSThread isMainThread], @"Must be in main thread.");
36 |
37 | static dispatch_once_t onceToken;
38 | dispatch_once(&onceToken, ^{
39 | leakedObjectPtrs = [[NSMutableSet alloc] init];
40 | });
41 |
42 | if (!ptrs.count) {
43 | return NO;
44 | }
45 | if ([leakedObjectPtrs intersectsSet:ptrs]) {
46 | return YES;
47 | } else {
48 | return NO;
49 | }
50 | }
51 |
52 | + (void)addLeakedObject:(id)object {
53 | NSAssert([NSThread isMainThread], @"Must be in main thread.");
54 |
55 | MLeakedObjectProxy *proxy = [[MLeakedObjectProxy alloc] init];
56 | proxy.object = object;
57 | proxy.objectPtr = @((uintptr_t)object);
58 | proxy.viewStack = [object viewStack];
59 | static const void *const kLeakedObjectProxyKey = &kLeakedObjectProxyKey;
60 | objc_setAssociatedObject(object, kLeakedObjectProxyKey, proxy, OBJC_ASSOCIATION_RETAIN);
61 |
62 | [leakedObjectPtrs addObject:proxy.objectPtr];
63 |
64 | #if _INTERNAL_MLF_RC_ENABLED
65 | [MLeaksMessenger alertWithTitle:@"Memory Leak"
66 | message:[NSString stringWithFormat:@"%@", proxy.viewStack]
67 | delegate:proxy
68 | additionalButtonTitle:@"Retain Cycle"];
69 | #else
70 | [MLeaksMessenger alertWithTitle:@"Memory Leak"
71 | message:[NSString stringWithFormat:@"%@", proxy.viewStack]];
72 | #endif
73 | }
74 |
75 | - (void)dealloc {
76 | NSNumber *objectPtr = _objectPtr;
77 | NSArray *viewStack = _viewStack;
78 | dispatch_async(dispatch_get_main_queue(), ^{
79 | [leakedObjectPtrs removeObject:objectPtr];
80 | [MLeaksMessenger alertWithTitle:@"Object Deallocated"
81 | message:[NSString stringWithFormat:@"%@", viewStack]];
82 | });
83 | }
84 |
85 | #pragma mark - UIAlertViewDelegate
86 |
87 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
88 | if (!buttonIndex) {
89 | return;
90 | }
91 |
92 | id object = self.object;
93 | if (!object) {
94 | return;
95 | }
96 |
97 | #if _INTERNAL_MLF_RC_ENABLED
98 | dispatch_async(dispatch_get_global_queue(0, 0), ^{
99 | FBRetainCycleDetector *detector = [FBRetainCycleDetector new];
100 | [detector addCandidate:self.object];
101 | NSSet *retainCycles = [detector findRetainCyclesWithMaxCycleLength:20];
102 |
103 | BOOL hasFound = NO;
104 | for (NSArray *retainCycle in retainCycles) {
105 | NSInteger index = 0;
106 | for (FBObjectiveCGraphElement *element in retainCycle) {
107 | if (element.object == object) {
108 | NSArray *shiftedRetainCycle = [self shiftArray:retainCycle toIndex:index];
109 |
110 | dispatch_async(dispatch_get_main_queue(), ^{
111 | [MLeaksMessenger alertWithTitle:@"Retain Cycle"
112 | message:[NSString stringWithFormat:@"%@", shiftedRetainCycle]];
113 | });
114 | hasFound = YES;
115 | break;
116 | }
117 |
118 | ++index;
119 | }
120 | if (hasFound) {
121 | break;
122 | }
123 | }
124 | if (!hasFound) {
125 | dispatch_async(dispatch_get_main_queue(), ^{
126 | [MLeaksMessenger alertWithTitle:@"Retain Cycle"
127 | message:@"Fail to find a retain cycle"];
128 | });
129 | }
130 | });
131 | #endif
132 | }
133 |
134 | - (NSArray *)shiftArray:(NSArray *)array toIndex:(NSInteger)index {
135 | if (index == 0) {
136 | return array;
137 | }
138 |
139 | NSRange range = NSMakeRange(index, array.count - index);
140 | NSMutableArray *result = [[array subarrayWithRange:range] mutableCopy];
141 | [result addObjectsFromArray:[array subarrayWithRange:NSMakeRange(0, index)]];
142 | return result;
143 | }
144 |
145 | @end
146 |
--------------------------------------------------------------------------------
/MLeaksFinder/NSObject+MemoryLeak.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Tencent is pleased to support the open source community by making MLeaksFinder available.
3 | *
4 | * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://opensource.org/licenses/BSD-3-Clause
9 | *
10 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
11 | */
12 |
13 | #import "NSObject+MemoryLeak.h"
14 | #import "MLeakedObjectProxy.h"
15 | #import "MLeaksFinder.h"
16 | #import
17 | #import
18 |
19 | #if _INTERNAL_MLF_RC_ENABLED
20 | #import
21 | #endif
22 |
23 | static const void *const kViewStackKey = &kViewStackKey;
24 | static const void *const kParentPtrsKey = &kParentPtrsKey;
25 | const void *const kLatestSenderKey = &kLatestSenderKey;
26 | const void *const kDelegateKey = &kDelegateKey;
27 |
28 | @implementation NSObject (MemoryLeak)
29 |
30 | - (BOOL)willDealloc {
31 | NSString *className = NSStringFromClass([self class]);
32 | if ([[NSObject classNamesWhitelist] containsObject:className])
33 | return NO;
34 |
35 | NSNumber *senderPtr = objc_getAssociatedObject([UIApplication sharedApplication], kLatestSenderKey);
36 | if ([senderPtr isEqualToNumber:@((uintptr_t)self)])
37 | return NO;
38 |
39 | __weak id weakSelf = self;
40 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
41 | __strong id strongSelf = weakSelf;
42 | [strongSelf assertNotDealloc];
43 | });
44 |
45 | return YES;
46 | }
47 |
48 | - (void)assertNotDealloc {
49 | if ([MLeakedObjectProxy isAnyObjectLeakedAtPtrs:[self parentPtrs]]) {
50 | return;
51 | }
52 | [MLeakedObjectProxy addLeakedObject:self];
53 |
54 | NSString *className = NSStringFromClass([self class]);
55 | NSLog(@"Possibly Memory Leak.\nIn case that %@ should not be dealloced, override -willDealloc in %@ by returning NO.\nView-ViewController stack: %@", className, className, [self viewStack]);
56 | }
57 |
58 | - (void)willReleaseObject:(id)object relationship:(NSString *)relationship {
59 | if ([relationship hasPrefix:@"self"]) {
60 | relationship = [relationship stringByReplacingCharactersInRange:NSMakeRange(0, 4) withString:@""];
61 | }
62 | NSString *className = NSStringFromClass([object class]);
63 | className = [NSString stringWithFormat:@"%@(%@), ", relationship, className];
64 |
65 | [object setViewStack:[[self viewStack] arrayByAddingObject:className]];
66 | [object setParentPtrs:[[self parentPtrs] setByAddingObject:@((uintptr_t)object)]];
67 | [object willDealloc];
68 | }
69 |
70 | - (void)willReleaseChild:(id)child {
71 | if (!child) {
72 | return;
73 | }
74 |
75 | [self willReleaseChildren:@[ child ]];
76 | }
77 |
78 | - (void)willReleaseChildren:(NSArray *)children {
79 | NSArray *viewStack = [self viewStack];
80 | NSSet *parentPtrs = [self parentPtrs];
81 | for (id child in children) {
82 | NSString *className = NSStringFromClass([child class]);
83 | [child setViewStack:[viewStack arrayByAddingObject:className]];
84 | [child setParentPtrs:[parentPtrs setByAddingObject:@((uintptr_t)child)]];
85 | [child willDealloc];
86 | }
87 | }
88 |
89 | - (NSArray *)viewStack {
90 | NSArray *viewStack = objc_getAssociatedObject(self, kViewStackKey);
91 | if (viewStack) {
92 | return viewStack;
93 | }
94 |
95 | NSString *className = NSStringFromClass([self class]);
96 | return @[ className ];
97 | }
98 |
99 | - (void)setViewStack:(NSArray *)viewStack {
100 | objc_setAssociatedObject(self, kViewStackKey, viewStack, OBJC_ASSOCIATION_RETAIN);
101 | }
102 |
103 | - (NSSet *)parentPtrs {
104 | NSSet *parentPtrs = objc_getAssociatedObject(self, kParentPtrsKey);
105 | if (!parentPtrs) {
106 | parentPtrs = [[NSSet alloc] initWithObjects:@((uintptr_t)self), nil];
107 | }
108 | return parentPtrs;
109 | }
110 |
111 | - (void)setParentPtrs:(NSSet *)parentPtrs {
112 | objc_setAssociatedObject(self, kParentPtrsKey, parentPtrs, OBJC_ASSOCIATION_RETAIN);
113 | }
114 |
115 | + (void)setDelegate:(id)delegate {
116 | objc_setAssociatedObject([NSObject class], kDelegateKey, delegate, OBJC_ASSOCIATION_RETAIN);
117 | }
118 |
119 | + (NSMutableSet *)classNamesWhitelist {
120 | static NSMutableSet *whitelist = nil;
121 | static dispatch_once_t onceToken;
122 | dispatch_once(&onceToken, ^{
123 | whitelist = [NSMutableSet setWithObjects:
124 | @"UIFieldEditor", // UIAlertControllerTextField
125 | @"UINavigationBar",
126 | @"_UIAlertControllerActionView",
127 | @"_UIVisualEffectBackdropView",
128 | nil];
129 |
130 | // System's bug since iOS 10 and not fixed yet up to this ci.
131 | NSString *systemVersion = [UIDevice currentDevice].systemVersion;
132 | if ([systemVersion compare:@"10.0" options:NSNumericSearch] != NSOrderedAscending) {
133 | [whitelist addObject:@"UISwitch"];
134 | }
135 | });
136 | return whitelist;
137 | }
138 |
139 | + (void)addClassNamesToWhitelist:(NSArray *)classNames {
140 | [[self classNamesWhitelist] addObjectsFromArray:classNames];
141 | }
142 |
143 | + (void)swizzleSEL:(SEL)originalSEL withSEL:(SEL)swizzledSEL {
144 | #if _INTERNAL_MLF_ENABLED
145 |
146 | #if _INTERNAL_MLF_RC_ENABLED
147 | // Just find a place to set up FBRetainCycleDetector.
148 | static dispatch_once_t onceToken;
149 | dispatch_once(&onceToken, ^{
150 | dispatch_async(dispatch_get_main_queue(), ^{
151 | [FBAssociationManager hook];
152 | });
153 | });
154 | #endif
155 |
156 | Class class = [self class];
157 |
158 | Method originalMethod = class_getInstanceMethod(class, originalSEL);
159 | Method swizzledMethod = class_getInstanceMethod(class, swizzledSEL);
160 |
161 | BOOL didAddMethod =
162 | class_addMethod(class,
163 | originalSEL,
164 | method_getImplementation(swizzledMethod),
165 | method_getTypeEncoding(swizzledMethod));
166 |
167 | if (didAddMethod) {
168 | class_replaceMethod(class,
169 | swizzledSEL,
170 | method_getImplementation(originalMethod),
171 | method_getTypeEncoding(originalMethod));
172 | } else {
173 | method_exchangeImplementations(originalMethod, swizzledMethod);
174 | }
175 | #endif
176 | }
177 |
178 | @end
179 |
--------------------------------------------------------------------------------
/MLeaksFinder.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B32AAB321D767E59001485FF /* UITouch+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B32AAB311D767E59001485FF /* UITouch+MemoryLeak.m */; };
11 | B3667E4E1D38ADF6002B55DE /* MLeakedObjectProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = B3667E4D1D38ADF6002B55DE /* MLeakedObjectProxy.m */; };
12 | B3667E721D3BA78E002B55DE /* MLeaksMessenger.m in Sources */ = {isa = PBXBuildFile; fileRef = B3667E711D3BA78E002B55DE /* MLeaksMessenger.m */; };
13 | B367C8971C1C029500FDA5A9 /* NSObject+MemoryLeak.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = B3ADE17B1C1BD2F000AA4F63 /* NSObject+MemoryLeak.h */; };
14 | B3ADE1701C1BD1D600AA4F63 /* MLeaksFinder.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = B3ADE16F1C1BD1D600AA4F63 /* MLeaksFinder.h */; };
15 | B3ADE17A1C1BD29600AA4F63 /* UIView+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3ADE1791C1BD29600AA4F63 /* UIView+MemoryLeak.m */; };
16 | B3ADE17D1C1BD2F000AA4F63 /* NSObject+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3ADE17C1C1BD2F000AA4F63 /* NSObject+MemoryLeak.m */; };
17 | B3ADE1801C1BD4B200AA4F63 /* UIViewController+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3ADE17F1C1BD4B200AA4F63 /* UIViewController+MemoryLeak.m */; };
18 | B3ADE1831C1BD54B00AA4F63 /* UINavigationController+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3ADE1821C1BD54B00AA4F63 /* UINavigationController+MemoryLeak.m */; };
19 | B3ADE1861C1BD5CC00AA4F63 /* UIPageViewController+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3ADE1851C1BD5CC00AA4F63 /* UIPageViewController+MemoryLeak.m */; };
20 | B3ADE1891C1BD6F000AA4F63 /* UITabBarController+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3ADE1881C1BD6F000AA4F63 /* UITabBarController+MemoryLeak.m */; };
21 | B3ADE18C1C1BD74700AA4F63 /* UISplitViewController+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3ADE18B1C1BD74700AA4F63 /* UISplitViewController+MemoryLeak.m */; };
22 | B3C512C51CE3368B0032C2C8 /* UIApplication+MemoryLeak.m in Sources */ = {isa = PBXBuildFile; fileRef = B3C512C41CE3368B0032C2C8 /* UIApplication+MemoryLeak.m */; };
23 | FE6CAD555020A33B697B5FDE /* libPods-MLeaksFinder.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C69FD6BA6E3CCAC5168D790 /* libPods-MLeaksFinder.a */; };
24 | /* End PBXBuildFile section */
25 |
26 | /* Begin PBXCopyFilesBuildPhase section */
27 | B3ADE16A1C1BD1D600AA4F63 /* CopyFiles */ = {
28 | isa = PBXCopyFilesBuildPhase;
29 | buildActionMask = 2147483647;
30 | dstPath = "include/$(PRODUCT_NAME)";
31 | dstSubfolderSpec = 16;
32 | files = (
33 | B367C8971C1C029500FDA5A9 /* NSObject+MemoryLeak.h in CopyFiles */,
34 | B3ADE1701C1BD1D600AA4F63 /* MLeaksFinder.h in CopyFiles */,
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXCopyFilesBuildPhase section */
39 |
40 | /* Begin PBXFileReference section */
41 | 5E297F00748C1FFA737EEFB0 /* Pods-MLeaksFinder.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MLeaksFinder.release.xcconfig"; path = "Pods/Target Support Files/Pods-MLeaksFinder/Pods-MLeaksFinder.release.xcconfig"; sourceTree = ""; };
42 | 6C69FD6BA6E3CCAC5168D790 /* libPods-MLeaksFinder.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MLeaksFinder.a"; sourceTree = BUILT_PRODUCTS_DIR; };
43 | 90EF182415984ED6E908B442 /* Pods-MLeaksFinder.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MLeaksFinder.debug.xcconfig"; path = "Pods/Target Support Files/Pods-MLeaksFinder/Pods-MLeaksFinder.debug.xcconfig"; sourceTree = ""; };
44 | B32AAB301D767E59001485FF /* UITouch+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITouch+MemoryLeak.h"; sourceTree = ""; };
45 | B32AAB311D767E59001485FF /* UITouch+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITouch+MemoryLeak.m"; sourceTree = ""; };
46 | B3667E4C1D38ADF6002B55DE /* MLeakedObjectProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLeakedObjectProxy.h; sourceTree = ""; };
47 | B3667E4D1D38ADF6002B55DE /* MLeakedObjectProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLeakedObjectProxy.m; sourceTree = ""; };
48 | B3667E701D3BA78E002B55DE /* MLeaksMessenger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLeaksMessenger.h; sourceTree = ""; };
49 | B3667E711D3BA78E002B55DE /* MLeaksMessenger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLeaksMessenger.m; sourceTree = ""; };
50 | B3ADE16C1C1BD1D600AA4F63 /* libMLeaksFinder.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMLeaksFinder.a; sourceTree = BUILT_PRODUCTS_DIR; };
51 | B3ADE16F1C1BD1D600AA4F63 /* MLeaksFinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MLeaksFinder.h; sourceTree = ""; };
52 | B3ADE1781C1BD29600AA4F63 /* UIView+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+MemoryLeak.h"; sourceTree = ""; };
53 | B3ADE1791C1BD29600AA4F63 /* UIView+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+MemoryLeak.m"; sourceTree = ""; };
54 | B3ADE17B1C1BD2F000AA4F63 /* NSObject+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+MemoryLeak.h"; sourceTree = ""; };
55 | B3ADE17C1C1BD2F000AA4F63 /* NSObject+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+MemoryLeak.m"; sourceTree = ""; };
56 | B3ADE17E1C1BD4B200AA4F63 /* UIViewController+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+MemoryLeak.h"; sourceTree = ""; };
57 | B3ADE17F1C1BD4B200AA4F63 /* UIViewController+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+MemoryLeak.m"; sourceTree = ""; };
58 | B3ADE1811C1BD54B00AA4F63 /* UINavigationController+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UINavigationController+MemoryLeak.h"; sourceTree = ""; };
59 | B3ADE1821C1BD54B00AA4F63 /* UINavigationController+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UINavigationController+MemoryLeak.m"; sourceTree = ""; };
60 | B3ADE1841C1BD5CC00AA4F63 /* UIPageViewController+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIPageViewController+MemoryLeak.h"; sourceTree = ""; };
61 | B3ADE1851C1BD5CC00AA4F63 /* UIPageViewController+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIPageViewController+MemoryLeak.m"; sourceTree = ""; };
62 | B3ADE1871C1BD6F000AA4F63 /* UITabBarController+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITabBarController+MemoryLeak.h"; sourceTree = ""; };
63 | B3ADE1881C1BD6F000AA4F63 /* UITabBarController+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITabBarController+MemoryLeak.m"; sourceTree = ""; };
64 | B3ADE18A1C1BD74700AA4F63 /* UISplitViewController+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UISplitViewController+MemoryLeak.h"; sourceTree = ""; };
65 | B3ADE18B1C1BD74700AA4F63 /* UISplitViewController+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UISplitViewController+MemoryLeak.m"; sourceTree = ""; };
66 | B3C512C31CE3368B0032C2C8 /* UIApplication+MemoryLeak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIApplication+MemoryLeak.h"; sourceTree = ""; };
67 | B3C512C41CE3368B0032C2C8 /* UIApplication+MemoryLeak.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIApplication+MemoryLeak.m"; sourceTree = ""; };
68 | /* End PBXFileReference section */
69 |
70 | /* Begin PBXFrameworksBuildPhase section */
71 | B3ADE1691C1BD1D600AA4F63 /* Frameworks */ = {
72 | isa = PBXFrameworksBuildPhase;
73 | buildActionMask = 2147483647;
74 | files = (
75 | FE6CAD555020A33B697B5FDE /* libPods-MLeaksFinder.a in Frameworks */,
76 | );
77 | runOnlyForDeploymentPostprocessing = 0;
78 | };
79 | /* End PBXFrameworksBuildPhase section */
80 |
81 | /* Begin PBXGroup section */
82 | B3ADE1631C1BD1D600AA4F63 = {
83 | isa = PBXGroup;
84 | children = (
85 | B3ADE16E1C1BD1D600AA4F63 /* MLeaksFinder */,
86 | B3ADE16D1C1BD1D600AA4F63 /* Products */,
87 | F2E3CE8BD1BB1CB88838AF63 /* Pods */,
88 | E3247A573B2F7B1C26211F01 /* Frameworks */,
89 | );
90 | sourceTree = "";
91 | };
92 | B3ADE16D1C1BD1D600AA4F63 /* Products */ = {
93 | isa = PBXGroup;
94 | children = (
95 | B3ADE16C1C1BD1D600AA4F63 /* libMLeaksFinder.a */,
96 | );
97 | name = Products;
98 | sourceTree = "";
99 | };
100 | B3ADE16E1C1BD1D600AA4F63 /* MLeaksFinder */ = {
101 | isa = PBXGroup;
102 | children = (
103 | B3667E4C1D38ADF6002B55DE /* MLeakedObjectProxy.h */,
104 | B3667E4D1D38ADF6002B55DE /* MLeakedObjectProxy.m */,
105 | B3ADE16F1C1BD1D600AA4F63 /* MLeaksFinder.h */,
106 | B3667E701D3BA78E002B55DE /* MLeaksMessenger.h */,
107 | B3667E711D3BA78E002B55DE /* MLeaksMessenger.m */,
108 | B3ADE17B1C1BD2F000AA4F63 /* NSObject+MemoryLeak.h */,
109 | B3ADE17C1C1BD2F000AA4F63 /* NSObject+MemoryLeak.m */,
110 | B3C512C31CE3368B0032C2C8 /* UIApplication+MemoryLeak.h */,
111 | B3C512C41CE3368B0032C2C8 /* UIApplication+MemoryLeak.m */,
112 | B3ADE1811C1BD54B00AA4F63 /* UINavigationController+MemoryLeak.h */,
113 | B3ADE1821C1BD54B00AA4F63 /* UINavigationController+MemoryLeak.m */,
114 | B3ADE1841C1BD5CC00AA4F63 /* UIPageViewController+MemoryLeak.h */,
115 | B3ADE1851C1BD5CC00AA4F63 /* UIPageViewController+MemoryLeak.m */,
116 | B3ADE18A1C1BD74700AA4F63 /* UISplitViewController+MemoryLeak.h */,
117 | B3ADE18B1C1BD74700AA4F63 /* UISplitViewController+MemoryLeak.m */,
118 | B3ADE1871C1BD6F000AA4F63 /* UITabBarController+MemoryLeak.h */,
119 | B3ADE1881C1BD6F000AA4F63 /* UITabBarController+MemoryLeak.m */,
120 | B3ADE1781C1BD29600AA4F63 /* UIView+MemoryLeak.h */,
121 | B3ADE1791C1BD29600AA4F63 /* UIView+MemoryLeak.m */,
122 | B3ADE17E1C1BD4B200AA4F63 /* UIViewController+MemoryLeak.h */,
123 | B3ADE17F1C1BD4B200AA4F63 /* UIViewController+MemoryLeak.m */,
124 | B32AAB301D767E59001485FF /* UITouch+MemoryLeak.h */,
125 | B32AAB311D767E59001485FF /* UITouch+MemoryLeak.m */,
126 | );
127 | path = MLeaksFinder;
128 | sourceTree = "";
129 | };
130 | E3247A573B2F7B1C26211F01 /* Frameworks */ = {
131 | isa = PBXGroup;
132 | children = (
133 | 6C69FD6BA6E3CCAC5168D790 /* libPods-MLeaksFinder.a */,
134 | );
135 | name = Frameworks;
136 | sourceTree = "";
137 | };
138 | F2E3CE8BD1BB1CB88838AF63 /* Pods */ = {
139 | isa = PBXGroup;
140 | children = (
141 | 90EF182415984ED6E908B442 /* Pods-MLeaksFinder.debug.xcconfig */,
142 | 5E297F00748C1FFA737EEFB0 /* Pods-MLeaksFinder.release.xcconfig */,
143 | );
144 | name = Pods;
145 | sourceTree = "";
146 | };
147 | /* End PBXGroup section */
148 |
149 | /* Begin PBXNativeTarget section */
150 | B3ADE16B1C1BD1D600AA4F63 /* MLeaksFinder */ = {
151 | isa = PBXNativeTarget;
152 | buildConfigurationList = B3ADE1751C1BD1D600AA4F63 /* Build configuration list for PBXNativeTarget "MLeaksFinder" */;
153 | buildPhases = (
154 | 1E51A1E3538164E48103EBFB /* 📦 Check Pods Manifest.lock */,
155 | B3ADE1681C1BD1D600AA4F63 /* Sources */,
156 | B3ADE1691C1BD1D600AA4F63 /* Frameworks */,
157 | B3ADE16A1C1BD1D600AA4F63 /* CopyFiles */,
158 | C5C5444B869098CC15440C05 /* 📦 Copy Pods Resources */,
159 | );
160 | buildRules = (
161 | );
162 | dependencies = (
163 | );
164 | name = MLeaksFinder;
165 | productName = MLeaksFinder;
166 | productReference = B3ADE16C1C1BD1D600AA4F63 /* libMLeaksFinder.a */;
167 | productType = "com.apple.product-type.library.static";
168 | };
169 | /* End PBXNativeTarget section */
170 |
171 | /* Begin PBXProject section */
172 | B3ADE1641C1BD1D600AA4F63 /* Project object */ = {
173 | isa = PBXProject;
174 | attributes = {
175 | LastUpgradeCheck = 0710;
176 | ORGANIZATIONNAME = zeposhe;
177 | TargetAttributes = {
178 | B3ADE16B1C1BD1D600AA4F63 = {
179 | CreatedOnToolsVersion = 7.1.1;
180 | };
181 | };
182 | };
183 | buildConfigurationList = B3ADE1671C1BD1D600AA4F63 /* Build configuration list for PBXProject "MLeaksFinder" */;
184 | compatibilityVersion = "Xcode 3.2";
185 | developmentRegion = English;
186 | hasScannedForEncodings = 0;
187 | knownRegions = (
188 | en,
189 | );
190 | mainGroup = B3ADE1631C1BD1D600AA4F63;
191 | productRefGroup = B3ADE16D1C1BD1D600AA4F63 /* Products */;
192 | projectDirPath = "";
193 | projectRoot = "";
194 | targets = (
195 | B3ADE16B1C1BD1D600AA4F63 /* MLeaksFinder */,
196 | );
197 | };
198 | /* End PBXProject section */
199 |
200 | /* Begin PBXShellScriptBuildPhase section */
201 | 1E51A1E3538164E48103EBFB /* 📦 Check Pods Manifest.lock */ = {
202 | isa = PBXShellScriptBuildPhase;
203 | buildActionMask = 2147483647;
204 | files = (
205 | );
206 | inputPaths = (
207 | );
208 | name = "📦 Check Pods Manifest.lock";
209 | outputPaths = (
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | shellPath = /bin/sh;
213 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
214 | showEnvVarsInLog = 0;
215 | };
216 | C5C5444B869098CC15440C05 /* 📦 Copy Pods Resources */ = {
217 | isa = PBXShellScriptBuildPhase;
218 | buildActionMask = 2147483647;
219 | files = (
220 | );
221 | inputPaths = (
222 | );
223 | name = "📦 Copy Pods Resources";
224 | outputPaths = (
225 | );
226 | runOnlyForDeploymentPostprocessing = 0;
227 | shellPath = /bin/sh;
228 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MLeaksFinder/Pods-MLeaksFinder-resources.sh\"\n";
229 | showEnvVarsInLog = 0;
230 | };
231 | /* End PBXShellScriptBuildPhase section */
232 |
233 | /* Begin PBXSourcesBuildPhase section */
234 | B3ADE1681C1BD1D600AA4F63 /* Sources */ = {
235 | isa = PBXSourcesBuildPhase;
236 | buildActionMask = 2147483647;
237 | files = (
238 | B3C512C51CE3368B0032C2C8 /* UIApplication+MemoryLeak.m in Sources */,
239 | B3ADE17A1C1BD29600AA4F63 /* UIView+MemoryLeak.m in Sources */,
240 | B3ADE1861C1BD5CC00AA4F63 /* UIPageViewController+MemoryLeak.m in Sources */,
241 | B3667E4E1D38ADF6002B55DE /* MLeakedObjectProxy.m in Sources */,
242 | B3667E721D3BA78E002B55DE /* MLeaksMessenger.m in Sources */,
243 | B3ADE17D1C1BD2F000AA4F63 /* NSObject+MemoryLeak.m in Sources */,
244 | B3ADE18C1C1BD74700AA4F63 /* UISplitViewController+MemoryLeak.m in Sources */,
245 | B3ADE1801C1BD4B200AA4F63 /* UIViewController+MemoryLeak.m in Sources */,
246 | B3ADE1831C1BD54B00AA4F63 /* UINavigationController+MemoryLeak.m in Sources */,
247 | B32AAB321D767E59001485FF /* UITouch+MemoryLeak.m in Sources */,
248 | B3ADE1891C1BD6F000AA4F63 /* UITabBarController+MemoryLeak.m in Sources */,
249 | );
250 | runOnlyForDeploymentPostprocessing = 0;
251 | };
252 | /* End PBXSourcesBuildPhase section */
253 |
254 | /* Begin XCBuildConfiguration section */
255 | B3ADE1731C1BD1D600AA4F63 /* Debug */ = {
256 | isa = XCBuildConfiguration;
257 | buildSettings = {
258 | ALWAYS_SEARCH_USER_PATHS = NO;
259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
260 | CLANG_CXX_LIBRARY = "libc++";
261 | CLANG_ENABLE_MODULES = YES;
262 | CLANG_ENABLE_OBJC_ARC = YES;
263 | CLANG_WARN_BOOL_CONVERSION = YES;
264 | CLANG_WARN_CONSTANT_CONVERSION = YES;
265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
266 | CLANG_WARN_EMPTY_BODY = YES;
267 | CLANG_WARN_ENUM_CONVERSION = YES;
268 | CLANG_WARN_INT_CONVERSION = YES;
269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
270 | CLANG_WARN_UNREACHABLE_CODE = YES;
271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
272 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
273 | COPY_PHASE_STRIP = NO;
274 | DEBUG_INFORMATION_FORMAT = dwarf;
275 | ENABLE_STRICT_OBJC_MSGSEND = YES;
276 | ENABLE_TESTABILITY = YES;
277 | GCC_C_LANGUAGE_STANDARD = gnu99;
278 | GCC_DYNAMIC_NO_PIC = NO;
279 | GCC_NO_COMMON_BLOCKS = YES;
280 | GCC_OPTIMIZATION_LEVEL = 0;
281 | GCC_PREPROCESSOR_DEFINITIONS = (
282 | "DEBUG=1",
283 | "$(inherited)",
284 | );
285 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
286 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
287 | GCC_WARN_UNDECLARED_SELECTOR = YES;
288 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
289 | GCC_WARN_UNUSED_FUNCTION = YES;
290 | GCC_WARN_UNUSED_VARIABLE = YES;
291 | IPHONEOS_DEPLOYMENT_TARGET = 6.0;
292 | MTL_ENABLE_DEBUG_INFO = YES;
293 | ONLY_ACTIVE_ARCH = YES;
294 | SDKROOT = iphoneos;
295 | };
296 | name = Debug;
297 | };
298 | B3ADE1741C1BD1D600AA4F63 /* Release */ = {
299 | isa = XCBuildConfiguration;
300 | buildSettings = {
301 | ALWAYS_SEARCH_USER_PATHS = NO;
302 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
303 | CLANG_CXX_LIBRARY = "libc++";
304 | CLANG_ENABLE_MODULES = YES;
305 | CLANG_ENABLE_OBJC_ARC = YES;
306 | CLANG_WARN_BOOL_CONVERSION = YES;
307 | CLANG_WARN_CONSTANT_CONVERSION = YES;
308 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
309 | CLANG_WARN_EMPTY_BODY = YES;
310 | CLANG_WARN_ENUM_CONVERSION = YES;
311 | CLANG_WARN_INT_CONVERSION = YES;
312 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
313 | CLANG_WARN_UNREACHABLE_CODE = YES;
314 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
315 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
316 | COPY_PHASE_STRIP = NO;
317 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
318 | ENABLE_NS_ASSERTIONS = NO;
319 | ENABLE_STRICT_OBJC_MSGSEND = YES;
320 | GCC_C_LANGUAGE_STANDARD = gnu99;
321 | GCC_NO_COMMON_BLOCKS = YES;
322 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
323 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
324 | GCC_WARN_UNDECLARED_SELECTOR = YES;
325 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
326 | GCC_WARN_UNUSED_FUNCTION = YES;
327 | GCC_WARN_UNUSED_VARIABLE = YES;
328 | IPHONEOS_DEPLOYMENT_TARGET = 6.0;
329 | MTL_ENABLE_DEBUG_INFO = NO;
330 | SDKROOT = iphoneos;
331 | VALIDATE_PRODUCT = YES;
332 | };
333 | name = Release;
334 | };
335 | B3ADE1761C1BD1D600AA4F63 /* Debug */ = {
336 | isa = XCBuildConfiguration;
337 | baseConfigurationReference = 90EF182415984ED6E908B442 /* Pods-MLeaksFinder.debug.xcconfig */;
338 | buildSettings = {
339 | OTHER_LDFLAGS = "-ObjC";
340 | PRODUCT_NAME = "$(TARGET_NAME)";
341 | SKIP_INSTALL = YES;
342 | };
343 | name = Debug;
344 | };
345 | B3ADE1771C1BD1D600AA4F63 /* Release */ = {
346 | isa = XCBuildConfiguration;
347 | baseConfigurationReference = 5E297F00748C1FFA737EEFB0 /* Pods-MLeaksFinder.release.xcconfig */;
348 | buildSettings = {
349 | OTHER_LDFLAGS = "-ObjC";
350 | PRODUCT_NAME = "$(TARGET_NAME)";
351 | SKIP_INSTALL = YES;
352 | };
353 | name = Release;
354 | };
355 | /* End XCBuildConfiguration section */
356 |
357 | /* Begin XCConfigurationList section */
358 | B3ADE1671C1BD1D600AA4F63 /* Build configuration list for PBXProject "MLeaksFinder" */ = {
359 | isa = XCConfigurationList;
360 | buildConfigurations = (
361 | B3ADE1731C1BD1D600AA4F63 /* Debug */,
362 | B3ADE1741C1BD1D600AA4F63 /* Release */,
363 | );
364 | defaultConfigurationIsVisible = 0;
365 | defaultConfigurationName = Release;
366 | };
367 | B3ADE1751C1BD1D600AA4F63 /* Build configuration list for PBXNativeTarget "MLeaksFinder" */ = {
368 | isa = XCConfigurationList;
369 | buildConfigurations = (
370 | B3ADE1761C1BD1D600AA4F63 /* Debug */,
371 | B3ADE1771C1BD1D600AA4F63 /* Release */,
372 | );
373 | defaultConfigurationIsVisible = 0;
374 | defaultConfigurationName = Release;
375 | };
376 | /* End XCConfigurationList section */
377 | };
378 | rootObject = B3ADE1641C1BD1D600AA4F63 /* Project object */;
379 | }
380 |
--------------------------------------------------------------------------------