Skip to content

Commit 9110a4f

Browse files
author
Christian Menschel
committed
Merge branch 'development'
2 parents 1e6a659 + 1962c0c commit 9110a4f

9 files changed

+71
-28
lines changed

HeapInspector/HINSPDebug.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ NS_ASSUME_NONNULL_BEGIN
1717
/// Stops the HeapInspector and removes the inspector's view
1818
+ (void)stop;
1919

20+
// Shows HeapInspector (if not visible yet) and starts the record immediately
21+
+ (void)startRecord;
22+
23+
// Stops record - but does not hide the HeapInspector
24+
+ (void)stopRecord;
25+
2026
/// Add some (or only one) class prefix like `UI` OR `MK` to record classes that match the prefix only.
2127
/// It's highly recommended to record a specific class or prefix -
2228
/// otherwise all Cocoa classes will be recorded, which slows down the performance.

HeapInspector/HINSPDebug.m

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ - (HINSPHeapStackTableViewController *)heapStackControllerWithHeapStack:(NSArray
118118

119119
- (void)stopRecord
120120
{
121+
_window.recordButton.isRecording = NO;
121122
_recordedHeap = [HINSPHeapStackInspector recordedHeap];
122123
[self showInfoLabel];
123124
[NSObject endSnapshot];
@@ -128,6 +129,7 @@ - (void)beginRecord
128129
_recordedHeap = nil;
129130
[self resetInfoLabel];
130131
[NSObject beginSnapshot];
132+
_window.recordButton.isRecording = YES;
131133
[HINSPHeapStackInspector performHeapShot];
132134
}
133135

@@ -138,6 +140,14 @@ + (void)start
138140
twDebug = [[HINSPDebug alloc] init];
139141
}
140142

143+
+ (void)startRecord
144+
{
145+
if (!twDebug) {
146+
[self start];
147+
}
148+
[twDebug beginRecord];
149+
}
150+
141151
+ (void)stop
142152
{
143153
[NSObject endSnapshot];
@@ -146,6 +156,10 @@ + (void)stop
146156
twDebug = nil;
147157
}
148158

159+
+ (void)stopRecord {
160+
[twDebug stopRecord];
161+
}
162+
149163
+ (void)addClassPrefixesToRecord:(NSArray <NSString *> *)classPrefixes
150164
{
151165
if (classPrefixes) {

HeapInspector/HINSPHeapStackDetailTableViewController.m

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ - (void)updateHeaderView
104104
{
105105
if ([self.inspectingObject conformsToProtocol:@protocol(NSObject)] &&
106106
[self.inspectingObject respondsToSelector:@selector(description)]) {
107-
_headerTextView.text = [self.inspectingObject description];
107+
NSInteger retainCount = CFGetRetainCount((__bridge CFTypeRef)self.inspectingObject);
108+
NSString *retainCountString = [NSString stringWithFormat:@"Retain count: %ld\n", (long)retainCount];
109+
NSString *infoHeaderText = [retainCountString stringByAppendingString:[self.inspectingObject description]];
110+
_headerTextView.text = infoHeaderText;
108111
}
109112
}
110113

HeapInspector/HINSPHeapStackInspector.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
#import <Foundation/Foundation.h>
1010

11-
typedef void (^RMHeapEnumeratorBlock)(__unsafe_unretained id object);
11+
typedef void (^RMHeapEnumeratorBlock)(__unsafe_unretained id object, BOOL *stop);
1212

1313
@interface HINSPHeapStackInspector : NSObject
1414

HeapInspector/HINSPHeapStackInspector.m

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ static inline void range_callback(task_t task,
3737
vm_range_t *ranges,
3838
unsigned rangeCount)
3939
{
40-
RMHeapEnumeratorBlock block = (__bridge RMHeapEnumeratorBlock)context;
41-
if (!block) {
40+
RMHeapEnumeratorBlock enumeratorBlock = (__bridge RMHeapEnumeratorBlock)context;
41+
if (!enumeratorBlock) {
4242
return;
4343
}
44+
BOOL stop = NO;
4445
for (unsigned int i = 0; i < rangeCount; i++) {
4546
vm_range_t range = ranges[i];
4647
rm_maybe_object_t *object = (rm_maybe_object_t *)range.address;
@@ -55,20 +56,23 @@ static inline void range_callback(task_t task,
5556
if (tryClass &&
5657
CFSetContainsValue(classesLoadedInRuntime, (__bridge const void *)(tryClass)) &&
5758
canRecordObject((__bridge id)object)) {
58-
block((__bridge id)object);
59+
enumeratorBlock((__bridge id)object, &stop);
60+
if (stop) {
61+
break;
62+
}
5963
}
6064
}
6165
}
6266

63-
+ (void)enumerateLiveObjectsUsingBlock:(RMHeapEnumeratorBlock)block
67+
+ (void)enumerateLiveObjectsUsingBlock:(RMHeapEnumeratorBlock)completionBlock
6468
{
65-
if (!block) {
69+
if (!completionBlock) {
6670
return;
6771
}
6872

6973
// Refresh the class list on every call in case classes are added to the runtime.
7074
[self updateRegisteredClasses];
71-
75+
7276
// For another exmple of enumerating through malloc ranges (which helped my understanding of the api) see:
7377
// http://llvm.org/svn/llvm-project/lldb/tags/RELEASE_34/final/examples/darwin/heap_find/heap/heap_find.cpp
7478
// Also https://gist.github.com/samdmarshall/17f4e66b5e2e579fd396
@@ -77,16 +81,27 @@ + (void)enumerateLiveObjectsUsingBlock:(RMHeapEnumeratorBlock)block
7781
mach_port_t task = mach_task_self();
7882
unsigned int zoneCount = 0;
7983
kern_return_t result = malloc_get_all_zones(task, memory_reader, &zones, &zoneCount);
84+
BOOL __block stopEnumerator = NO;
8085
if (result == KERN_SUCCESS) {
8186
for (unsigned i = 0; i < zoneCount; i++) {
8287
malloc_zone_t *zone = (malloc_zone_t *)zones[i];
8388
if (zone != NULL && zone->introspect != NULL) {
84-
zone->introspect->enumerator(task,
85-
(__bridge void *)(block),
86-
MALLOC_PTR_IN_USE_RANGE_TYPE,
87-
(vm_address_t)zone,
88-
memory_reader,
89-
range_callback);
89+
RMHeapEnumeratorBlock enumeratorBlock = ^(__unsafe_unretained id object, BOOL *stop) {
90+
completionBlock(object, &stopEnumerator);
91+
if (stopEnumerator) {
92+
*stop = YES;
93+
}
94+
};
95+
if (!stopEnumerator) {
96+
zone->introspect->enumerator(task,
97+
(__bridge void *)(enumeratorBlock),
98+
MALLOC_PTR_IN_USE_RANGE_TYPE,
99+
(vm_address_t)zone,
100+
memory_reader,
101+
range_callback);
102+
} else {
103+
break;
104+
}
90105
}
91106
}
92107
}
@@ -132,7 +147,7 @@ + (NSSet *)recordedHeap
132147
+ (NSSet *)heap
133148
{
134149
NSMutableSet *objects = [NSMutableSet set];
135-
[HINSPHeapStackInspector enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object) {
150+
[HINSPHeapStackInspector enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, BOOL *stop) {
136151
// We cannot store the object itself - We want to avoid any retain calls.
137152
// We store the class name + pointer
138153
NSString *string = [NSString stringWithFormat:@"%s: %p",
@@ -147,12 +162,13 @@ + (NSSet *)heap
147162
+ (id)objectForPointer:(NSString *)pointer
148163
{
149164
id __block foundObject = nil;
150-
[HINSPHeapStackInspector enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object) {
165+
[HINSPHeapStackInspector enumerateLiveObjectsUsingBlock:^(__unsafe_unretained id object, BOOL *stop) {
151166
if ([pointer isEqualToString:[NSString stringWithFormat:@"%p",object]]) {
167+
152168
foundObject = object;
169+
*stop = YES;
153170
}
154171
}];
155-
156172
return foundObject;
157173
}
158174

HeapInspector/HINSPRecordButton.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99
#import <UIKit/UIKit.h>
1010

1111
@interface HINSPRecordButton : UIControl
12-
12+
@property (nonatomic) BOOL isRecording;
1313
@end

HeapInspector/HINSPRecordButton.m

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010

1111

1212
@interface HINSPRecordButton ()
13-
14-
@property (nonatomic) BOOL isRecording;
1513
@property (nonatomic, weak) CAShapeLayer *shapeLayer;
1614
@end
1715

@@ -31,13 +29,19 @@ - (instancetype)initWithFrame:(CGRect)frame
3129
- (void)tapped:(id)sender
3230
{
3331
self.isRecording = !self.isRecording;
34-
UIColor *color = nil;
35-
if (self.isRecording) {
36-
color = [self recordingColor];
37-
} else {
38-
color = [self defaultColor];
32+
}
33+
34+
- (void)setIsRecording:(BOOL)isRecording {
35+
if (_isRecording != isRecording) {
36+
_isRecording = isRecording;
37+
UIColor *color = nil;
38+
if (isRecording) {
39+
color = [self recordingColor];
40+
} else {
41+
color = [self defaultColor];
42+
}
43+
_shapeLayer.fillColor = color.CGColor;
3944
}
40-
_shapeLayer.fillColor = color.CGColor;
4145
}
4246

4347
#pragma mark - Setter

HeapInspector/HINSPRefHistoryTableViewController.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ - (instancetype)initWithObject:(id)object
2525
self = [super initWithObject:object];
2626
if (self) {
2727

28-
self.title = [NSString stringWithFormat:@"Reference History: %s: %p",
28+
self.title = [NSString stringWithFormat:@"%s: %p",
2929
object_getClassName(self.inspectingObject),
3030
self.inspectingObject];
3131

HeapInspector/HINSPShowViewController.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ - (instancetype)initWithObject:(id)object
2929
self = [super init];
3030
if (self) {
3131
self.title = @"Showing View";
32-
self.edgesForExtendedLayout = UIRectEdgeNone;
32+
self.automaticallyAdjustsScrollViewInsets = YES;
3333
_objectToInspect = object;
3434
self.shouldShowEditButton = YES;
3535
}

0 commit comments

Comments
 (0)