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

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?

Related

setHidden not working for UIView

I have a subclass of UIView called InvitedView. It is instantiated in viewDidLoad like this:
ViewController.m
invitedView = [[InvitedView alloc] initWithFrame:CGRectMake(100, 244, 120, 80)];
invitedView.backgroundColor = [UIColor colorWithRed:156.0f/255.0f green:214.0f/255.0f blue:215.0f/255.0f alpha:0.9f];
[self.view addSubview:invitedView];
[invitedView setHidden:YES];
The class itself looks like this:
InvitedView.m
#import "InvitedView.h"
#import "AppDelegate.h"
#import "ViewController.h"
#class ViewController;
#interface InvitedView() {
UIButton *accept;
UIButton *decline;
UILabel *question;
UIView *gray;
ViewController *myViewController;
}
#end
#implementation InvitedView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
gray = [[UIView alloc] initWithFrame:frame];
NSString *holduser = [(AppDelegate*)[[UIApplication sharedApplication] delegate] invitedby];
[self addSubview:gray];
accept = [[UIButton alloc] init];
decline = [[UIButton alloc] init];
question = [[UILabel alloc] init];
question.text = [[NSString alloc] initWithFormat:#"You have been invited to a group game by %#", holduser];
question.numberOfLines = 0;
question.textAlignment = NSTextAlignmentCenter;
question.textColor = [UIColor colorWithRed:211.0f/255.0f green:243.0f/255.0f blue:219.0f/255.0f alpha:1.0f];
accept.backgroundColor = [UIColor clearColor];
accept.frame = CGRectMake(20, gray.frame.size.height / 2, (gray.frame.size.width / 2) - 10, (gray.frame.size.height / 2) - 20);
decline.backgroundColor = [UIColor clearColor];
decline.frame = CGRectMake((gray.frame.size.width / 2) + 10, (gray.frame.size.width / 2) - 20, (gray.frame.size.width / 2) - 20, (gray.frame.size.height / 2) - 20);
question.frame = CGRectMake(20, 20, gray.frame.size.width, (gray.frame.size.height / 2) - 20);
[question setFont:[UIFont fontWithName:#"HelveticaNeue-Bold" size:18.0]];
[accept addTarget:myViewController action:#selector(acceptInvite) forControlEvents:UIControlEventTouchUpInside];
[decline addTarget:myViewController action:#selector(declineInvite) forControlEvents:UIControlEventTouchUpInside];
[gray addSubview:accept];
[gray addSubview:decline];
[gray addSubview:question];
}
return self;
}
#end
The method where the view is supposed to be shown is in the view controller showing the view. It ends up getting called, I can verify that the log messages happen all the way up until the setHidden function:
ViewController.m
- (void)doSomethingWithTheNewValueOfFlagForHid {
NSLog(#"issettingtheview******");
dispatch_async(dispatch_get_main_queue(), ^(void){
NSLog(#"issettingtheviewmu2******");
[invitedView setHidden:NO];
});
}
I would like to know why invitedView isn't being shown after [invitedView setHidden:NO].
It gets all the way to setHidden, and then nothing happens. I would appreciate any help, thanks in advance.
In ViewDidLoad, change line to
[invitedView setHidden:NO];
to make sure you can actually see the view (frame is ok, no view above ...)
You might also want to check Xcodes 3D View Debugging
The only reason that it wasn't showing up, is that invitedView was being instantiated inside an if statement that wasn't being executed. However - shallowThought's idea to switch setHidden to YES started me down a more productive debugging tract, leading to the discovery.

is there a clear understanding of IQWidgets library

I am trying to build a gantt chart.
I found this library on https://github.com/evolvIQ/iqwidgets
I download it, I tried to understand how can I use it.
I have a class that bring the data(JSON) from a server. I am assigning these results as [NSDictionary].
I tried to use the IQGanttView.h file by adding it as a subview of my current view.
IQGanttView.h has a method called addRow:(id<IQCalendarDataSource>)row
The addRow method has an argument of IQCalendarDataSource which is why I created a class as an IQCalendarDataSource (Task object).
I change the IQCalendarDataSource class to have the same property of my task class.
After creating these tasks object, I have a for loop for all the array(tasks object) to add them through addRow:(id<IQCalendarDataSource>)row method to show up on the chart.
I ran the code and followed it but it's not showing me the tasks on the chart.
I don't know if i'm missing something?
Can someone check the library and tell me if i'm missing something?
=================
This is the code that I was trying.
#import "GanttChartViewController.h"
#import "ASRESTAPI.h"
#import "ASUserSingleton.h"
#import "TasksObj.h"
#import "IQGanttView.h"
// when the view load I want to show the user the loading view until the data is ready to show up on the chart by calling [self setupLoadingIndicator] method
//
- (void)viewDidLoad {
[super viewDidLoad];
tasksItems = [[NSArray alloc] init];
self.ganttView = [[IQGanttView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.ganttView];
[self setupLoadingIndicator];
// Do any additional setup after loading the
[self gettheTasksItems];
}
-(void)setupLoadingIndicator
{
loadingView = [[UIView alloc] initWithFrame:CGRectMake(75, 155, 170, 170)];
loadingView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
loadingView.clipsToBounds = YES;
loadingView.layer.cornerRadius = 10.0;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityView.frame = CGRectMake(65, 40, activityView.bounds.size.width, activityView.bounds.size.height);
[loadingView addSubview:activityView];
loadingLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 115, 130, 22)];
loadingLabel.backgroundColor = [UIColor clearColor];
loadingLabel.textColor = [UIColor whiteColor];
loadingLabel.adjustsFontSizeToFitWidth = YES;
loadingLabel.textAlignment = NSTextAlignmentCenter;
loadingLabel.text = #"Loading...";
[loadingView addSubview:loadingLabel];
[self.ganttView addSubview:loadingView];
[activityView startAnimating];
}
-(void)gettheTasksItems
{
NSString* username = [[ASUserSingleton sharedInstance]userName];
NSString* password = [[ASUserSingleton sharedInstance]password];
_tasks = nil;
[ASRESTAPI tasksListUsername:username andPassword:password completionBlock:^(NSDictionary *response, NSArray *taskArray) {
_tasks = response;
tasksItems = taskArray;
NSMutableArray *tasksObjs = [NSMutableArray array];
int i;
for (i =0; i < tasksItems.count;i++)
{
/*_tasks[#"project"][#"name"]*/ // this is how to call the dictionary object from the array
TasksObj* tasksObj = [[TasksObj alloc]initWithProjectName:tasksItems[i][#"project"][#"name"]
startDate:tasksItems[i][#"start_date"]
dueDate:tasksItems[i][#"due_date"]
estimatedhours:tasksItems[i][#"estimated_hours"]];
//tasksItems[i] objectForKey:#"project"];
[tasksObjs addObject:tasksObj];
}
dispatch_async(dispatch_get_main_queue(), ^{
[activityView stopAnimating];
for (loadingView in [self.ganttView subviews])
{
[loadingView removeFromSuperview];
}
//[loadingView removeFromSuperview];
for (TasksObj* tasksObj in tasksObjs) {
[self.ganttView addRow:tasksObj];
}
});
}];
}
The reason that I'm using dispatch_async(dispatch_get_main_queue() is to make sure that the UI element is shown, i've learned that if I want the UI element to be shown then I have to make it through the main queue.
This is the class of TasksObj
#interface TasksObj : NSObject <IQCalendarDataSource>
#property (nonatomic, strong) NSString* projectName;
#property (nonatomic, strong) NSDate* start_date;
#property (nonatomic, strong) NSDate* due_date;
#property (nonatomic, strong) NSNumber* estimated_hours;
-(id)initWithProjectName:(NSString*)projectName startDate:(NSDate*)start_date dueDate:(NSDate*)due_date estimatedhours:(NSNumber*)estimated_hours;
#end
#implementation TasksObj
-(id)initWithProjectName:(NSString*)projectName startDate:(NSDate*)start_date dueDate:(NSDate*)due_date estimatedhours:(NSNumber*)estimated_hours
{
self = [super init];
if (self) {
self.projectName = projectName;
self.start_date = start_date;
self.due_date = due_date;
self.estimated_hours = estimated_hours;
}
return self;
}
#end
by the way this is the JSON data that i'm getting from the server
"task":
{
"id":1,
"project":{"id":1,"name":"test"},
"tracker":{"id":1,"name":"Bug"},
"status":{"id":1,"name":"New"},
"priority":{"id":4,"name":"Urgent"},
"author":{"id":1,"name":"the user name"},
"subject":"Example",
"description":"",
"start_date":"2016-02-17",
"due_date":"2016-02-23",
"done_ratio":0,
"estimated_hours":3.0,
"spent_hours":0.0,
"created_on":"2016-02-18T04:28:55Z",
"updated_on":"2016-02-22T19:09:22Z"
}

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.

Why UILabel increasing memory usage?

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.

Determine if current screen has visible navigation bar

I have a singlton object. Is there any simple way to determine if current screen contains a navigation bar within singlton methods?
The singleton is UIView subclass. It's designed for showing prorgess activity, e.g. network exchange. It looks like black rectangle dropping down from top and hiding when the work is done. Why singleton? It's easy to call it from any place of code
The followed snippet is showing the initialization of activity singleton and published here just for better understaning my idea.
-(void) showUpdatingView:(NSString *) msg {
[self initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)];
activity = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] autorelease];
activity.frame = CGRectMake(5, 10, 22, 22);
labelView = [[[UILabel alloc] initWithFrame:CGRectMake(35, 10, [UIScreen mainScreen].bounds.size.width - 10, 22)] autorelease];
labelView.font = [UIFont boldSystemFontOfSize:12];
labelView.backgroundColor = [UIColor clearColor];
labelView.textColor = [UIColor whiteColor];
labelView.text = msg;
[self addSubview:activity];
[self addSubview:labelView];
self.backgroundColor = [UIColor blackColor];
self.alpha = 0.7;
}
The activity can be called by
[[ActivitySingleton getInstance] showUpdatingView:#"Getting data."];
it's not all.
The singleton is being created in AppDelegate object and the view is added to
inlineActivity = [[CHInlineActivityView alloc] initView];
[self.window.rootViewController.view addSubview:inlineActivity];
I know it may look crazy. But when I was designing it seemed to me reasonable
if you have all in one navigationController:
BOOL navHidden = self.window.rootViewController.navigationController.navigatonBarHidden;
if you don't it is a bit harder.. you could check the window's subviews and see if you can find a UINavigationBar
id navbar = [self.window firstSubviewOfKind:[UINavigationBar class] withTag:NSNotFound];
BOOL navHidden = navbar == nil;
#implementation NSView (findSubview)
- (NSArray *)findSubviewsOfKind:(Class)kind withTag:(NSInteger)tag inView:(NSView*)v {
NSMutableArray *array = [NSMutableArray array];
if(kind==nil || [v isKindOfClass:kind]) {
if(tag==NSNotFound || v.tag==tag) {
[array addObject:v];
}
}
for (id subview in v.subviews) {
NSArray *vChild = [self findSubviewsOfKind:kind withTag:tag inView:subview];
[array addObjectsFromArray:vChild];
}
return array;
}
#pragma mark -
- (NSView *)firstSubviewOfKind:(Class)kind withTag:(NSInteger)tag {
NSArray *subviews = [self findSubviewsOfKind:kind withTag:tag inView:self];
return subviews.count ? subviews[0] : nil;
}
#end

Resources