Why UILabel increasing memory usage? - ios

So, i have some boundaries (addBoundaryWithIdentifier:), a have code which generate blocks (UIView squares) every second with performSelector:, the blocks fall and if collision with boundary happened i remove item.
Now, if i add UILabel to view, memory usage slowly increase up to 15Mb and then stop climbing.
Memory using without UILabel:
Memory using with UILabel:
Memory using with UILabel after couple minutes:
What's going on here? How to fix that? Should i fix that?
This is the code I'm using.
#implementation ESViewController {
UIPushBehavior *pushBlock;
UIDynamicAnimator *mainAnimator;
UICollisionBehavior *blockCollision;
}
- (void)viewDidLoad {
[super viewDidLoad];
// UILabel *label = [[UILabel alloc] initWithFrame: CGRectMake(110, 400, 100, 50)];
// [label setText:#"Hello"];
// [label setTextAlignment: NSTextAlignmentCenter];
// [self.view addSubview: label];
mainAnimator = [[UIDynamicAnimator alloc] initWithReferenceView: self.view];
blockCollision = [[UICollisionBehavior alloc] initWithItems: #[]];
[blockCollision addBoundaryWithIdentifier:#"bottom"
fromPoint:CGPointMake(0, 480)
toPoint:CGPointMake(320, 480)];
[blockCollision addBoundaryWithIdentifier:#"left"
fromPoint:CGPointMake(0, 480)
toPoint:CGPointMake(0, 0)];
[blockCollision addBoundaryWithIdentifier:#"right"
fromPoint:CGPointMake(320, 480)
toPoint:CGPointMake(320, 0)];
[blockCollision addBoundaryWithIdentifier:#"top"
fromPoint:CGPointMake(0, -40)
toPoint:CGPointMake(320, -40)];
[blockCollision setCollisionDelegate: (id<UICollisionBehaviorDelegate>)self];
[mainAnimator addBehavior: blockCollision];
pushBlock = [[UIPushBehavior alloc] initWithItems: #[] mode: UIPushBehaviorModeContinuous];
[pushBlock setAngle: M_PI/2 magnitude:0.05];
[mainAnimator addBehavior: pushBlock];
[self movingBlocks];
}
- (void) movingBlocks {
UIView *block = [[UIView alloc] initWithFrame:CGRectMake(arc4random() % 320, -20, 20, 20)];
[block setBackgroundColor: [UIColor brownColor]];
[self.view addSubview: block];
[blockCollision addItem: block];
[pushBlock addItem: block];
[self performSelector:#selector(movingBlocks) withObject:nil afterDelay:0.05];
}
- (void)collisionBehavior:(UICollisionBehavior *)behavior
beganContactForItem:(id<UIDynamicItem>)item
withBoundaryIdentifier:(id<NSCopying>)identifier
atPoint:(CGPoint)p {
[pushBlock removeItem:item];
[blockCollision removeItem:item];
[(UIView*)item removeFromSuperview];
}
#end

I've reproduced the symptom you're describing, but I believe Xcode is lying to you and you should open a radar (bugreport.apple.com).
If you run this in Instruments, memory usage is exactly as you would expect. I've tried having Xcode profile in Release mode (like Instruments does), and I've run on all the iPad simulators. The symptom is very reproducible in Xcode, while Instruments shows expected results and is very stable. I even transferred a running process that was showing growth in Xcode over to Instruments, and Instruments still shows no growth. I'd say Xcode is busted here.

Related

UILabel is not shown in custom UIView screen

Here is how I implemented my custom UiView
In myView.h file
#interface myView : UIView
{
NSString *message;
}
...
#property (nonatomic, retain) UILabel *messageLabel;
...
#end
In myView.m file
This function will instantiate myView and add the message label to it
+ (id) initWithText:(NSString *) text
{
screenBounds = [[UIScreen mainScreen] bounds];
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
self = [super initWithFrame:CGRectMake(0, statusBarFrame.size.height, screenBounds.size.width, 40)];
if (self)
{
[self setBackgroundColor:[UIColor redColor]];
message = [text copy];
_messageLabel = [[UILabel alloc]initWithFrame:[self frame]];
[_messageLabel setText:message];
[_messageLabel setAdjustsFontSizeToFitWidth:YES];
[_messageLabel setTextAlignment:NSTextAlignmentJustified];
[_messageLabel setTextColor:[ UIColor blackColor]];
[self addSubview:_messageLabel];
}
return self;
}
Later I add myView as a subclass to the visible view in my screen. When I run the app I can see the red coloured myView but message label is not displayed in it.
When you init your UILabel with self.frame, you have to consider the value inside its parent view.
Maybe your 2nd parameter: y = statusBarFrame.size.height is to high and that's why your label is out your view ?
Try to init your label with CGRectMake(0,0,self.frame.width, self.frame.height)
check if text you are setting in label is blank and
_messageLabel = [[UILabel alloc]initWithFrame:self.frame];
I Tried this code And it worked. Sure that you didn't set other parameters to your UILabel somewhere else ? These are the differences with your code :
I replaced your '+' by '-' for the method.
I changed uilabel frame for initialisation.
Added a background color to label (only to check).
-(id)initWithText:(NSString *)text
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
self = [super initWithFrame:CGRectMake(0, statusBarFrame.size.height, screenBounds.size.width, 40)];
if (self) {
[self setBackgroundColor:[UIColor redColor]];
NSString *message = [text copy];
UILabel *_messageLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[_messageLabel setText:message];
[_messageLabel setBackgroundColor:[UIColor lightTextColor]];
[_messageLabel setAdjustsFontSizeToFitWidth:YES];
[_messageLabel setTextAlignment:NSTextAlignmentJustified];
[_messageLabel setTextColor:[ UIColor blackColor]];
[self addSubview:_messageLabel];
}
return self;
}
Before: I used to call initWithText() & show() from backgroundOP.m file where I do background operations. These functions are always executed in separate threads.
Now: I moved the call to initWithText() & show() method inside a delegate method and added the delegate to presenting UIViewController i.e., inside the viewController.m file in which I want my view to appear. Now I call this delegate from another file (i.e., from backgroundOP.m) and problem is solved. Now both UIView and UILabel is visible in screen.
But I don't understand why adding the UIView from the background thread function shows only the UIView and not its contents/subviews.
In my show() function, I use this dispatch queue to add the myView to presenting key window. Like below code
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
dispatch_async(dispatch_get_main_queue(), ^{
[window addSubview:self]; // self represents myView object
});
If someones knows the reason for this behaviour, please enlighten me.

I alloc a viewcontroller without init , but why everything works fine

I alloc a viewcontroller without init it, but everything works fine. The subviews in the viewcontroller work fine.
Here is the code.
self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
self.window.rootViewController = [[UINavigationController alloc]initWithRootViewController:[ViewController alloc]];
The code in ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self test];
}
- (void)test
{
self.view.backgroundColor = [UIColor whiteColor];
CGRect frame = CGRectMake( 50, 100, 200, 200);
UIScrollView *scrollView= [[UIScrollView alloc] initWithFrame:frame];
[self.view addSubview:scrollView];
frame= CGRectMake( 0, 0, 500, 500);
UIImageView *myImageView= [[UIImageView alloc] initWithFrame:frame];
[scrollView addSubview:myImageView];
scrollView.contentSize = CGSizeMake(500,500);
scrollView.backgroundColor = [UIColor blackColor];
myImageView.backgroundColor = [UIColor yellowColor];
scrollView.contentOffset = CGPointMake(0, 0);
}
#end
Avi got it right in (his?) comment. It's dumb luck. This is like saying "I've been driving my car for 30,000 km without changing the oil and it's running fine. Why does everybody say you have to change your oil?"
Init does the setup for a class, and it's ancestor classes. It's fairly certain that there is some setup that isn't getting done that will cause problems in the future.
The proper way to create an object is with alloc/init. If you don't do that, "the result is undefined."

iOS Zombie - can't figure out why object is released

I'm trying to debug some code that has a exc_bad_access crash. It appears I have a zombie, but I can't figure out why the object is being deallocated. It is a Unity3D project, built for iOS. The code in question is in a .mm file, so ObjectiveC++.
So Instruments shows the function that is being deallocated, but I don't really understand what is happening. The Responsible Caller is a function called LoadVideo, which is wrapped in an 'extern "C"'. The code is below:
extern "C"
{
void LoadVideo()
{
// get the current UIViewController
UIViewController *viewController = UnityGetGLViewController();
// create the videLoader object
VideoLoaderUIObject * vidLoader = [VideoLoaderUIObject new];
// start up our loading screen
gSavingVideoAlert = [[CustomIOS7AlertView alloc] init];
UIView* uiViewLoading = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 125)];
UILabel* loadingLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 300, 40)];
loadingLabel.numberOfLines = 2;
[loadingLabel setText:#"Loading videos\nPlease Wait..."];
[loadingLabel setTextAlignment:NSTextAlignmentCenter];
[loadingLabel setTextColor:[UIColor blackColor]];
[loadingLabel setBackgroundColor:[UIColor clearColor]];
[loadingLabel setFont:[UIFont fontWithName: #"Trebuchet MS" size: 14.0f]];
[uiViewLoading addSubview:loadingLabel];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
// Adjust the indicator so it is up a few pixels from the bottom of the alert
indicator.center = CGPointMake(uiViewLoading.bounds.size.width / 2, uiViewLoading.bounds.size.height - 50);
[indicator startAnimating];
[uiViewLoading addSubview:indicator];
[gSavingVideoAlert setContainerView:uiViewLoading];
[gSavingVideoAlert show];
// open the media gallery
[vidLoader startMediaBrowserFromViewController: viewController usingDelegate: vidLoader];
#ifdef DEBUG_LOGS
NSLog(#"video path %#", [vidLoader VideoPath]);
#endif
}
}
The problem seems to be at this line:
[vidLoader startMediaBrowserFromViewController: viewController usingDelegate: vidLoader];
The vidLoader object is from a VideoLoaderUIObject class, defined as:
#interface VideoLoaderUIObject : UIImagePickerController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
#private
bool mIsUsingCam;
NSMutableArray* mAssets;
NSMutableArray *mVidIPod;
NSMutableArray *mVidItems;
std::vector<UIInterfaceOrientation> mVidOrientations;
MyCustomViewController* mScrollViewController;
}
The output from Instruments is below:
What's stopping the vidLoader object being retained?

MPVolumeView animation issue

Every time I add MPVolumeView as a subview to my UIViewController’s view, there is a quick animation (the MPVolumeView expands from left to right) which looks really weird. I’m looking for a way to get rid of this animation, has anyone faced this issue?
I almost accepted that this is a MPVolumeView bug but then I noticed that Apple is definitely using a MPVolumeView in their native music app, no weird animations there...
So there must be something I'm doing wrong.
UPDATE:
The code is pretty straightforward but it was requested in the comments, so here it is:
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(10.f, 0.f, CGRectGetWidth(self.view.frame) - 20.f, 30.f)];
[[UISlider appearanceWhenContainedIn:[MPVolumeView class], nil] setMinimumValueImage:[UIImage imageNamed:#"icon-volumeMin"]];
[[UISlider appearanceWhenContainedIn:[MPVolumeView class], nil] setMaximumValueImage:[UIImage imageNamed:#"icon-volumeMax"]];
volumeView.center = CGPointMake(0.5f * CGRectGetWidth(self.view.frame), 0.5f * CGRectGetHeight(self.view.frame));
volumeView.showsRouteButton = NO;
[self.view addSubview:volumeView];
I made a very simple project on github to demostrate the problem, but you have to run it on a device, since MPVolumeView does not show up on simulator. Or just take a look at this gif:
:
One possible way to remove this behavior is to subclass MPVolumeView and perform some additional work after [super layoutSubviews].
- (void)layoutSubviews
{
[super layoutSubviews];
[self xy_recursiveRemoveAnimationsOnView:self];
}
- (void)xy_recursiveRemoveAnimationsOnView:(UIView *)view
{
[view.layer removeAllAnimations];
for (UIView *subview in view.subviews) {
[self xy_recursiveRemoveAnimationsOnView:subview];
}
}
This removes all inserted animations. So be sure that is what you want, since this is quite the overkill. One could also just remove the position and bounds animations (see removeAnimationForKey:).
i fixed your demo-code
#implementation F17YViewController {
MPVolumeView *volumeView;
}
- (void)viewDidLoad {
[super viewDidLoad];
volumeView = [[MPVolumeView alloc] init];
volumeView.showsRouteButton = NO;
volumeView.hidden = true;
[[UISlider appearanceWhenContainedIn:[MPVolumeView class], nil] setMinimumValueImage:[UIImage imageNamed:#"icon-volumeMin"]];
[[UISlider appearanceWhenContainedIn:[MPVolumeView class], nil] setMaximumValueImage:[UIImage imageNamed:#"icon-volumeMax"]];
[self.view addSubview:volumeView];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
volumeView.frame = CGRectMake(10.f, 0.f, CGRectGetWidth(self.view.frame) - 20.f, 30.f);
volumeView.center = CGPointMake(0.5f * CGRectGetWidth(self.view.frame), 0.5f * CGRectGetHeight(self.view.frame));
}
- (IBAction)showVolumeView:(id)sender {
volumeView.hidden = false;
}
You should do layout calls in viewWillLayoutSubviews.
Instead of creating a new MPVolumeView with each button press you should create one at viewDidLoad and hide it and then unhide when the button gets pressed.

Centering a child UIView to its parent UIView

I want to center a subview in the middle of its parent, I have looked at answers on SO but so far they have not helped me. This one specifically looks like it should work, but doesn't.
Here is what I am doing
-(void)viewDidLoad {
[super viewDidLoad];
finalNumberCircle = [[CircleView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
finalNumberCircle.center = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2);
finalNumberCircle.Color = [UIColor darkGrayColor];
[self.view addSubview:finalNumberCircle];
}
I also tried the following:
-(void)viewDidLoad {
[super viewDidLoad];
CGPoint translatedP = [self.view convertPoint:self.view.center fromView:self.view.superview];
finalNumberCircle = [[CircleView alloc] initWithFrame:CGRectMake(0, 0, 100, 100];
finalNumberCircle.center = translatedP;
[self.view addSubView:finalNumberCircle];
}
Here is how it looks (it's the grey circle)
You have to move your code (2. example) from viewDidLoad to viewWillLayoutSubviews and it will work as suspected.
Before viewWillLayoutSubview is called your viewcontroller view bounds still can change.
convertPoint and related methods used when you want to convert coordinates from one view's coordinates to another, that's not your situation. You have to do something like:
finalNumberCircle = [[CircleView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
finalNumberCircle.center = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2);
[self.view addSubview:finalNumberCircle];
Try below code...
[self.view addSubView:finalNumberCircle];
finalNumberCircle.frame=CGRectMake(finalNumberCircle.frame.origin.x+(self.view.frame.size.width/2-finalNumberCircle.center.x), finalNumberCircle.frame.origin.y+(self.view.frame.size.height/2-finalNumberCircle.center.y), finalNumberCircle.frame.size.width, finalNumberCircle.frame.size.height);
Another possibility how to do it (in case You need specific offset from sides). Just provide an offset from parent view sides, and it will auto-resize itself in center of parent view, and will also autoresize, in case parent view frame is changed.
- (void)viewDidLoad
{
[super viewDidLoad];
CGFloat mOffsetFromSide = 50;
finalNumberCircle = [[CircleView alloc] initWithFrame:CGRectMake(self.view.bounds.origin.x+mOffsetFromSide, self.view.bounds.origin.y+mOffsetFromSide, self.view.bounds.size.width-mOffsetFromSide*2, self.view.bounds.size.height-mOffsetFromSide*2];
[finalNumberCircle setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)];
[self.view addSubView:finalNumberCircle];
}
In case You simply want to position view in it's parent view's center, leaving it's frame intact, then:
finalNumberCircle = [[CircleView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
finalNumberCircle.center = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2);
[self.view addSubview:finalNumberCircle];
And yes - it is exact copy of Your provided code. It works on my side.
Maybe problem is with CircleView itself. Or You change it's frame later in code?
What happens if You change "CircleView" to simply UIView ?
I think that you should move half width to the left, and half height upwards:
-(void)viewDidLoad {
[super viewDidLoad];
finalNumberCircle = [[CircleView alloc] initWithFrame:CGRectMake(self.view.center.x-50, self.view.center.y-50, 100, 100];
[self.view addSubView:finalNumberCircle];
}
But I would use something like:
#DEFINE CIRCLE_RADIUS 50
-(void)viewDidLoad {
[super viewDidLoad];
finalNumberCircle = [[CircleView alloc] initWithFrame:CGRectMake(self.view.center.x-CIRCLE_RADIUS, self.view.center.y-CIRCLE_RADIUS, 2*CIRCLE_RADIUS, 2*CIRCLE_RADIUS];
[self.view addSubView:finalNumberCircle];
}
I uploaded a demo https://github.com/luisespinoza/CenterViewTest

Resources