I have a small png that I am adding to a view which I am pretty sure I had working previously but suddenly stopped working on the iPad itself while continuing to work fine on the iPad simulator.
Here is the code I am using to add the image to the view...
UIImageView *bottomResizer = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"resizeLine.png"]];
bottomResizer.center = CGPointMake(bottomResizer.center.x, bottomResizer.center.y+self.frame.size.height-12);
bottomResizer.tag = 301;
[self addSubview:bottomResizer];
[bottomResizer release];
This occurs in a UIGestureRecognizerStateBegan event. The following code in removes the image in a touchesEnded event without any errors even though you cannot see it.
NSArray *subViews = [self subviews];
int count = [subViews count];
for (int i =count-1; i>=0; i--) {
if([[subViews objectAtIndex:i] tag] == 301) {
[[subViews objectAtIndex:i] removeFromSuperview];
}
}
I don't think it is anything I changed in my code since it works in the simulator. Not sure where to look next for the problem. I have reset the simulator to see if it would break after a reset. I have also cleaned the project.
Thanks.
John
Put a breakpoint AFTER this line UIImageView *bottomResizer = [[UIImageView alloc]...
Then on the console "po [bottomResizer image]"
If it is nil then either the resource is not getting copied correctly into the bundle OR you could have a corrupt image that the device cannot load.
Related
I dragged a texture atlas into my project. The pictures are named correctly ("heliani_1-9")
The animation is running smooth, except for 3 frames, which are displayed as big red cross on a white ground. (See screenshot enclosed)
What is wrong with my code?
Cheers
#import "MRMPlayer.h"
#implementation MRMPlayer
-(instancetype)init
{
self = [super init];
{
[self setupAnimations];
[self runAction:[SKAction repeatActionForever:[SKAction animateWithTextures:self.runFrames timePerFrame:0.5 resize:YES restore:NO]] withKey:#"heli"];
self.name = playerName;
}
return self;
}
-(void) setupAnimations{
self.runFrames = [[NSMutableArray alloc]init];
SKTextureAtlas *heliAtlas = [SKTextureAtlas atlasNamed:#"heli"];
for (int i = 0; i < [heliAtlas.textureNames count]; i++) {
NSString *tempName = [NSString stringWithFormat:#"heliani_%d",i];
SKTexture *tempTexture = [heliAtlas textureNamed:tempName];
if(tempTexture) {
[self.runFrames addObject:tempTexture];
}
}
}
#end
Go to the product menu, and you will see the Clean option.
Now, hold down the option button on your keyboard and the text should change to Clean build folder...
Choose that option, and it will additionally delete the derivative data folder that caches alot of things including the texture atlas, and I've found to cause problems like you have described. If you rename files in the atlas, thats typically when I have experienced this issue myself.
I don't like that this option is something you kind of have to work for, would be nice to have this second option there WITHOUT having to hold down the option key.
If this doesn't solve the problem, you truly have a naming problem imo.
Note
You can also delete the derivative data folders from the Organizer window.
I have written a small application, initially under OSX 10.8, that receives MIDI events via MidiEventCallback and puts the data into a NSMutableArray that is a member of a NSTableViewDataSource.
In this video you can see how it worked without any problems on OSX 10.8.
Now I have a new MacBook that runs on OSX 10.9, installed XCode and got all my project files and compiled the application.
Have connected my MIDI controller to my MacBook, started the application and pressing keys on the MIDI controller.
The problem:
The NSTableView is not being updated as it should. If I press my piano keys, no MIDI messages will be displayed and after a couple of seconds I get an exception. Here is a screenshot of what XCode is showing me then:
I stop the application and start it again. Now, when pressing keys, I resize the application window continuously and the NSTableView does update properly, no exception, everything fine.
Same when I press some piano keys a couple of times. Then bring some other application to the front and then my application to the front again. Again, all MIDI messages are displayed properly in my NSTableView.
Any idea what this can be? Is it a OSX 10.9 related issue or could it be with changing to a new MacBook. Am running out of options.
What I have tried is connecting the NSWindow of my application as an IBOutlet to my controller that acts as a NSTableViewDataSource and tried the following calls right after I did [tableView reloadData]
[window update]
[window display]
[window flushWindow]
but nothing helped. Any help highly appreciated.
EDIT
Did some more debugging following the comments and actually was looking at the wrong place.
Here some code for more context:
My controller has a property called MidiEventListener that receives all MIDI events and puts them into eventList.
#interface MidiAidController()
...
#property NSMutableArray *eventList;
#property MidiEventListener* listener;
#end
In the init method of my controller I do the following
_eventList = [[NSMutableArray alloc] init];
MidiEventCallback eventCallback = ^(MidiEvent* midiEvent)
{
[[self eventList] addObject:midiEvent];
[[self tableView] reloadData];
};
...
self.listener = [[MidiEventListener alloc] initWithCallback:eventCallback];
In MidiEventListener, within initWithCallback, the following happens:
result = MIDIInputPortCreate(_midiClient, CFSTR("Input"), midiInputCallback, (__bridge_retained void *)(self), &_inputPort);
Now, let's go over to midiInputCallback:
static void midiInputCallback(const MIDIPacketList* list, void *procRef, void *srcRef)
{
MidiEventListener *midiEventListener = (__bridge MidiEventListener*)procRef;
#autoreleasepool {
const MIDIPacket *packet = &list->packet[0];
for (unsigned int i = 0; i < list->numPackets; i++)
{
MidiEvent* midiEvent = [[MidiEvent alloc] initWithPacket:packet];
midiEventListener.midiEventCallback(midiEvent);
packet = MIDIPacketNext(packet);
}
}
}
That is basically it. The Exception happens at midiEventListener.midiEventCallback(midiEvent);. I always looked at *[tableView reloadData] since that was the line when clicking under Thread 6 - 19__25... (see screenshot above). But when I click on Thread 6 - 20 midiInputCallback then I get this line highlighted.
SOLUTION
Reloading the data has to be done from the main thread:
MidiEventCallback eventCallback = ^(MidiEvent* midiEvent)
{
[[self eventList] addObject:midiEvent];
dispatch_async(dispatch_get_main_queue(), ^(void){[[self tableView] reloadData];});
};
*Thread 6 - 19__25...* and reloadData
call reload only on Main Thread
e.g.
void MyCallback(...) {
dispatch_async(dispatch_get_main_queue(), ^{
...
}
}
I tried to add a AccessoryView to a NSSavePanel but sometimes the AccessoryView (it's elements) is disables and sometimes not. Hopefully anyone has a idea.
Here is my code:
NSWindow *window = [[NSApp delegate] window];
// Get savePath
NSSavePanel *spanel = [NSSavePanel savePanel];
__block SaveAccessoryViewController *saveAccessoryViewController = [[SaveAccessoryViewController alloc] initWithNibName:#"SaveAccessoryView" bundle:nil];
[spanel setAllowedFileTypes:[NSArray arrayWithObject:#"pdf"]];
[spanel setAccessoryView:saveAccessoryViewController.view];
[spanel beginSheetModalForWindow:window completionHandler:^(NSInteger returnCode) {
...
I had the same problem and I concluded that it had to do with ARC (Automatic Reference Count) settings for the project.
If you are using ARC make sure the settings are correct both on project and target.
In my case I had enabled ARC on target but not on project, after enabling ARC on project (and dealing with resulting errors and warnings) everything works perfectly now.
I have a detail view, and when viewdidload in detailviewcontroller, MPMoviePlayerController allocs and plays an audio, but even if I navigate backto main table, audio is still being played.
How can I stop MPMovieplayercontroller when I navigate back to main table ? This is my MPMoviePlayerController code:
.h
MPMoviePlayerController *player;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
//Get the Movie
NSURL *movieURL = [NSURL URLWithString:#"some link"];
player = [[MPMoviePlayerController alloc] initWithContentURL:movieURL];
//Place it in subview, else it won’t work
player.view.frame = CGRectMake(20, 20, 280, 25);
player.backgroundView.backgroundColor = [UIColor clearColor];
[self.view addSubview:player.view];
// Play the movie.
[player play];
}
I even added following code into viewdidunload method, but didn't work.
- (void)viewDidUnload {
[player stop];
player.initialPlaybackTime = -1;
[player release];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
What do you guys suggest ?
Thanks in advance,
I liked the user experience of viewDidDisappear better than viewWillDisappear. The animation starts and the movie stops after - the audio flows better for me this way.
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_moviePlayer stop];
}
I am having a similar issue. I am unable to use "viewDidDisappear" or "viewWillDisappear" because I have a "config" type view that can be opened while the content is playing, and it will trigger those two methods.
EDIT: Found that viewDidUnload and viewWillUnload are not getting called any more (I'm currently on an iOS 6+ device)...
From the documentation:
Availability: iOS (3.0 and later) Deprecated: Views are no longer
purged under low-memory conditions and so this method is never called.
I just created a simple function called unload, and inside the function, set any objects I needed to = nil (I'm using ARC). At the time that I make the call to remove the view, I call the unload function as well. Hope it helps someone.
I have an iPad application that can be used in all four view modes (portrait up/down and landscape left/right). But at a certain point I have a View that I only want to be seen in landscape mode. So I do the following in the UIViewController that will trigger the action to view the landscape-only view:
- (void) showProperty:(Property *) property {
if ([self interfaceOrientation] == UIInterfaceOrientationLandscapeLeft || [self interfaceOrientation] == UIInterfaceOrientationLandscapeRight) {
PropertyViewController *propertyView = [[PropertyViewController alloc] initWithNibName:#"PropertyViewController" bundle:[NSBundle mainBundle]];
propertyView.property = property;
[self.navigationController pushViewController:propertyView animated:YES];
[propertyView release];
propertyView = nil;
}
else {
RotateDeviceViewController *rotateView = [[RotateDeviceViewController alloc] initWithNibName:#"TabRotate" bundle: [NSBundle mainBundle]];
rotateView.property = property;
[self.navigationController pushViewController:rotateView animated:YES];
[rotateView release];
rotateView = nil;
}
}
This works fine and thus shows either the desired screen (PropertyViewController) when the iPad is held in landscape mode, and if not it shows the RotateDeviceViewController which shows the user a message that he/she is supposed to rotate the device to correctly view the screen.
So when the user then rotates his/her device to landscape mode I want to show them the right view (PropertyViewController). And all of this kinda works!
The problem arises though in this RotateDeviceViewController.. There I have the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
[self showProperty];
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
- (void) showProperty {
PropertyViewController *propertyView = [[PropertyViewController alloc] initWithNibName:#"PropertyViewController" bundle:[NSBundle mainBundle]];
propertyView.property = property;
[self.navigationController pushViewController:propertyView animated:YES];
[propertyView release];
}
So as soon as I rotate the device (when viewing the RotateDeviceViewController) to landscape mode I show the user the PropertyViewController. This works... But when the PropertyViewController appears it shows my layout 90 degrees rotated. So basically it shows the content in portrait mode instead of using the landscape mode (which is actually the way you are holding the device)..
I hope this makes sense and someone can show me what's causing this.
Screenshots to make it more clear:
When device is held in portrait mode
After rotating the device
At this point
- (BOOL)shouldAutorotateToInterfaceOrientation:UIInterfaceOrientation)interfaceOrientation
You are telling the view controller what orientations you support. The device has not actually rotated yet therefore the view controllers intefaceOrientation property will still be portrait so when it is pushed onto the stack it thinks the device is portrait.
pseudo code
shouldAutoRotate... // at this point self.interfaceOrientation == portrait
// you push your controller here so it loads when the property is
I'm not sure if this will work well but the earliest I can see you can push is in
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation