I have written a specific init-override-function where i want to pass an index number to be called in an array. The index number itself is defined by selecting a tablerow in a tableview by the user. So.. the rownumber that is selected shall be passed into the init function and used there for further processing.
Well.. now there is my problem.. In my opinion the methods I've created are all correctly coded. But when I click my defined Connect Button an error message appears in the console, that, the index is out of bounds. So.. I've checked the array for entries and there are all available. So the indexnumber should be fine.
Maybe fyi: I've created a copy of the array in the TableViewController that is originally located in the PortConnection file.
Here are the necessary files. Can anyone give me a helping hand, where to search for?
PORTTABLEVIEWCONTROLLER.M
- (IBAction)pushConnect:(id)sender {
NSInteger selectedRow = [tableView selectedRow];
[portConnection initPort:selectedRow];
}
- (id)init {
self = [super init];
if (self) {
// Initialization of port Connection instance
portConnection = [[PortConnection alloc] init];
// Fill array in Portconnection.m with devices
[portConnection listDevices];
// Fill tableView Data Array with data from portConnection array
self.tableViewDataArray = [NSMutableArray arrayWithArray:portConnection.portArray];
}
return self;
}
PORTCONNECTION.H
#
interface PortConnection : NSObject {
// Instance of AMSerialPort
AMSerialPort *port;
// Port Array to be filled with found ports
NSMutableArray *portArray;
}
// List Devices into an given array
- (void)listDevices;
// Connect to selected port
- (void)initPort:(NSInteger)selectedRow;
#property (nonatomic, retain) NSMutableArray *portArray;
#property (nonatomic, retain) AMSerialPort *port;
#end
PORTCONNECTION.M
#implementation PortConnection
#synthesize port;
#synthesize portArray;
#pragma mark -
#pragma mark Serial Port Access
- (void)listDevices {
// get an port enumerator
NSEnumerator *enumerator = [AMSerialPortList portEnumerator];
AMSerialPort *aPort;
while ((aPort = [enumerator nextObject])) {
[portArray addObject:[PortItem portItemWithTitle:[aPort name] andPath:[aPort bsdPath]]];
}
}
- (void)initPort:(NSInteger)selectedRow {
//Create object of selected port searched in array
PortItem *portSelected = [portArray objectAtIndex:selectedRow];
NSString *deviceNameSelected = [portSelected valueForKey:#"bsdPath"];
// Start Connection
if (![deviceNameSelected isEqualToString:[self.port bsdPath]]) {
[self.port close];
[self setPort:[[[AMSerialPort alloc] init:deviceNameSelected withName:deviceNameSelected type:(NSString *)CFSTR(kIOSerialBSDModemType)] autorelease]];
[self.port setDelegate:self.port];
if ([self.port open]) {
NSLog(#"Connected...");
[self.port setSpeed:B38400];
[self.port readDataInBackground];
} else {
NSLog(#"error connecting");
[self setPort:nil];
}
}
}
#pragma mark -
#pragma mark initialization / deallocation
- (id)init {
self = [super init];
if (self) {
portArray = [NSMutableArray array];
}
return self;
}
- (void)dealloc {
portArray = NULL;
[super dealloc];
}
#end
Well.. my idea is, that something is wrong with the method INITPORT:(NSINTEGER)SELECTEDROW
but I am not sure at all....
Thanks so much for giving me advice again!
Sebastian
Your problem is this line,
portArray = [NSMutableArray array];
Although it is a retained variable, it will retain the value when you use the property setter method. This is a direct assignment of an autoreleased object will be released in a while and baring any other object retaining it (which doesn't happen), it should get deallocated. This is something which you don't want. Remedy this by using the property setter,
self.portArray = [NSMutableArray array];
Related
I am facing a problem regarding to add Null or nil value in NSArray. Actually I am adding Null value because my array count is not same. I am adding three array in Custom TableViewCell two array are from webservice and one array is from database. I am saving IndexPath in core data and then retrieving it.
As shown in Image I am saving indexPath in String and convert it in NSInteger from DidSelectAtIndexPath and show it in cellForRowAtIndexPath. My problem is, it's getting override because it is stored in string. So that I save it in coredataa and retrieve it but I get problem for mismatch count of array in cellforrowatindexpath. My code is like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *STI=#"STI";
AuditTableViewCell *cell = (AuditTableViewCell *)[tableView dequeueReusableHeaderFooterViewWithIdentifier:STI];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"AuditTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
cell.accessoryType=UITableViewCellAccessoryNone;
}
cell.audittitlelbl.text=[NSString stringWithFormat:#"%#",[idarray objectAtIndex:indexPath.row]];
cell.auditdesclbl.text=[NSString stringWithFormat:#"%#",[namearray objectAtIndex:indexPath.row]];
NSManagedObject *device2 = [devices objectAtIndex:indexPath.row];
NSMutableArray *Checkarray=[devices valueForKey:#"Key"]; // Hear in this array I am getting Index count problem
NSLog(#"Device =%#",device2);
NSLog(#"Check Array =%#",Checkarray);
if(indexPath.row == CurrentIndexPath)
{
cell.listlbl.text=GlobalString;
[cell setBackgroundColor:[UIColor greenColor]];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CurrentIndexPath=indexPath.row;
NSLog(#"Current Index Path =%ld",(long)CurrentIndexPath);
GlobalIndexPath = [[NSString stringWithFormat: #"%ld", (long)CurrentIndexPath] mutableCopy];
NSManagedObjectContext *context = [self managedObjectContext];
if (self.device) {
// Update existing device
[device setValue:GlobalStringChk forKey:#"Key1"];
[device setValue:GlobalIndexPath forKey:#"Key"];
} else {
// Create a new device
NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:#"Device" inManagedObjectContext:context];
[newDevice setValue:GlobalStringChk forKey:#"Key1"];
[newDevice setValue:GlobalIndexPath forKey:#"Key"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[Audittable reloadData];
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Device"];
self.devices = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];
}
This is my code hear I am saving indexpath in coredata and retrieving it in array. I have a problem for count of array in cellforrowatindexpath. How can I add Null or nil value in array so that it count get same. My Array is a dynamic array.The main problem is that I need to change the colour of cell if user click on it.when I store the value in NSInteger and convert it into indexpath I can change the colour But only for one cell at a time.When I click on other cell integer value get override. So for that I save it to core data and retrive but when I fetch core data array in cellforrowatindexpath it crash because of different count .Thanks in Advance!
We cannot add nil directly inside a collection like NSMutableArray as it will raise an exception. If at all it is required to add nil inside collections like NSMutableArray, we can do so by using a singleton class NSNull.
For instance, we have a array of type NSMutableArray, we can add nil using NSNull as-
[array addObject:#"string"];
[array addObject:[NSNull null]];
...
and so on...
The NSNull class defines a singleton object used to represent null values in collection objects (which don’t allow nil values).
First you can't add elemets in NSArray, you must use NSMutableArray instead. Second thing you can not add nil in your NSMutableArray.
So, you should add empty string instead of nil something like,
NSMutableArray *arr = [[NSMutableArray alloc]init];
[arr addObject:#""];
or you can add NSNull Object like,
[arr addObject:[NSNull null]];
And you can check that string is empty or not when want to display in UI something like(if added empty string),
NSString *tempStr = [arr objectAtIndex:0];
if (tempStr.length > 0) {
NSLog(#"string is not empty.");
}
else{
NSLog(#"Sring is empty");
}
Ok I got your problem. You actually wants to merge data from 3 different array into one single cell, but the problem is your array count is different for each array. Yes you can do this but you have to change the way of coding.
Lets assume you have 3 arrays a1, a2 and a3, with counts:
a1.count = 5,
a2.count = 8,
a3.count = 10
Here I'm assuming a1 is array of NSString while a2 & a3 are arrays with numbers (NSIntegers)
Now create one simple class inheriting from NSObject. We call it as AuditTableViewDao. It is simple Data Access Object
#import <UIKit/UIKit.h>
#interface AuditTableViewDao : NSObject
#property (nonatomic) NSString *checkForWhat;
#property (nonatomic) NSString *methodMeasures;
#property (nonatomic) NSString *visualInspections;
- (instancetype)initWithCheckForWhat:(NSString *)checkForWhat methodMeasures:(NSString *)methodMeasures visualInspections:(NSString *)visualInspections;
#end
Then in .m file of this AuditTableViewDao.m, write implementation to initialize.
Then in your ViewComtroller.m file, create one property
#property (nonatomic) NSMutableArray *arrayAuditTableViews;
in viewDidLod, write
self.arrayAuditTableViews = [[NSMutableArray alloc] init];
for (NSInteger index=0; index < a3.count; index++) {
AuditTableViewDao *auditTableViewDao = nil;
if (index < a1.count) {
auditTableViewDao = [[AuditTableViewDao alloc] initWithCheckForWhat:((NSString *)[a1 objectAtIndex:index]) methodMeasures:[NSString stringWithFormat:#"%d", [a2 objectAtIndex:index]] visualInspections:[NSString stringWithFormat:#"%d", [a3 objectAtIndex:index]]];
}
else if (index < a2.count) {
auditTableViewDao = [[AuditTableViewDao alloc] initWithCheckForWhat:"" methodMeasures:[NSString stringWithFormat:#"%d", [a2 objectAtIndex:index]] visualInspections:[NSString stringWithFormat:#"%d", [a3 objectAtIndex:index]]];
}
else if (index < a3.count) {
auditTableViewDao = [[AuditTableViewDao alloc] initWithCheckForWhat:"" methodMeasures:"" visualInspections:[NSString stringWithFormat:#"%d", [a3 objectAtIndex:index]]];
}
[self.arrayAuditTableViews addObject:auditTableViewDao];
}
And finally in your cellForRowAtIndexPath, Use object of arrayAuditTableViews at perticular index path.
You need to add null in your array like this:
[yourArray addObject:[NSNull null]];
Add null
[array addObject:[NSNull null]];
nil is not an object that you can add to an array: An array cannot
contain nil. This is why addObject:nil crashes.
Don't need to save the index Path in core data and don't need to add Null or nill value.
Just alloc NSMutableArray in viewDidLoad method
NSMutableArray *_selectedIndexPath = [[NSMutableArray alloc] init];
Then in didSelectRowatIndexPath addObject in array like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (![_selectedIndexPath containsObject:indexPath]) { // Check if array does not contain selecting cell, add this cell to array
[_selectedIndexPath addObject:indexPath];
[tableView reloadData];
}
}
And then in Cellforrowatindexpath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([_selectedIndexPath containsObject:indexPath]) {
cell.backgroundColor=[UIColor greenColor];
}
else
{
cell.backgroundColor=[UIColor whiteColor];
}
}
And you can change your colour without using core data and null or nil value.
I have a fetchResultController that compiles an array by running through multiple methods. The final cells display a name and number (ranking). I'd like to take the cells from the tableview and sort them by the number (ascending). I've tried nssortdescriptor in the frc but run into issues when I try to call the 'ranking' because it isn't a keypath of the entity I'm fetching. Is there a place I can intercept this array that comes out of the frc to sort by valueForKey:#"ranking"? How would I implement this sort?
The methods it cycles through to create the valueForKey is here:
- (NSExpressionDescription*) rankingExpressionDescriptionForTags:(NSSet*)itemToTag
{
NSPredicate* p2 = [NSPredicate predicateWithFormat:#"SUBQUERY(itemToTag,$t,$t.tagName IN %#).#count > 0",[itemToTag valueForKey:#"tagName"]];
NSExpression* rankExpresion = [(NSComparisonPredicate*)p2 leftExpression];
NSExpressionDescription* rankExpDesc = [[NSExpressionDescription alloc] init];
rankExpDesc.name = #"ranking";
rankExpDesc.expression = rankExpresion;
rankExpDesc.expressionResultType = NSInteger64AttributeType;
return rankExpDesc;
}
- (NSExpressionDescription*) objectIDExpressionDescription
{
NSExpressionDescription* expDesc = [[NSExpressionDescription alloc] init];
expDesc.name = #"objectID";
expDesc.expressionResultType = NSObjectIDAttributeType;
expDesc.expression = [NSExpression expressionForEvaluatedObject];
return expDesc;
}
- (NSFetchRequest*) rankingRequestForItem:(Item*)item
{
NSFetchRequest* r = [NSFetchRequest fetchRequestWithEntityName:#"Item"];
NSPredicate* p = [NSPredicate predicateWithFormat:#"SELF != %#",item.objectID];
r.resultType = NSDictionaryResultType;
r.propertiesToFetch = #[[self objectIDExpressionDescription],#"itemName",
[self rankingExpressionDescriptionForTags:[item mutableSetValueForKey:#"itemToTag"]]];
r.predicate = p;
r.sortDescriptors = #[[NSSortDescriptor sortDescriptorWithKey:#"itemName" ascending:YES]];
return r;
}
and the frc with cell config is here:
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSLog(#"selected item: %#, itemToTag: %#",selectedItem.itemName,[selectedItem.itemToTag valueForKey:#"tagName"]);
NSFetchRequest *fetchRequest = [self rankingRequestForItem:selectedItem];
// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *item = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%# - %#",[item valueForKey:#"itemName"],[item valueForKey:#"ranking"]];
}
Thanks for the help!
As I explained HERE, there is no way (AFAIK) to sort based on the ranking expression. You will have to sort the results in-memory, thus nullifying completely the need for a FRC.
Simply execute the request on the given context and sort in-memory:
NSError* error = nil;
NSFetchRequest* r = [self rankingRequestForItem:selectedItem];
NSArray* results = [context executeFetchRequest:r error:&error];
NSSortDescriptor* sd = [NSSortDescriptor sortDescriptorWithKey:#"ranking" ascending:NO];
results = [results sortedArrayUsingDescriptors:#[sd]];
The results array will now hold your sorted information, use it as a datasource for your table.
Store the results in a view controller property like:
self.results = results;
This code might go in your viewDidLoad method for example.
everywhere you access the FRC to get an object, you now access your table datasource for that information (assuming you have only 1 section):
NSIndexPath* someIndexPath = //some index path you might get as parameter
[self.results objectAtIndex:someIndexPath.row]; //return NSDictionary
I'm using the Reachability class to detect wifi availability.
There are some situations when an ipad will be connected to one wifi network,and a user will connect to another available wifi network.
During these network transitions reachable->unreachable->reachable notifications are not generated.
This connection change where the ip address of the ipad changes is what Im trying to listen for.
Do notifications for local wifi connection changes exist or will I have to just poll my ip periodically?
I would personally just poll the IP however frequently you find appropriate (once a second should be fine), using the code found here, and just store the previous occurrences result, see if it changes.
What I would really recommend is setting up a simple delegate class that does this for you and will send a custom event to whatever class may need those updates. It should be pretty straight forward, especially considering it seems like you have some experience.
UPDATE
I have posted some code below that will create a delegate that will call back to whatever class once it detects any change in IP. Note there may be some errors/typos as I am not in front of a computer with XCode currently, but you should get the general idea.
IPChangeNotifier.h
#import <UIKit/UIKit.h>
#protocol IPChangeNotifierDelegate;
#interface IPChangeNotifier : NSObject {
NSString *prevIP;
NSTimer *changeTimer;
id changeDelegate;
}
-(id) initWithTimer:(float)time andDelegate:(id)del;
-(NSString*)getIPAddress;
-(void) checkForChange;
#end
#protocol IPChangeNotifierDelegate <NSObject>
#optional
-(void) IPChangeDetected:(NSString*)newIP previousIP:(NSString*)oldIP;
#end
IPChangeNotifier.m
#import IPChangeNotifier.h
#import <ifaddrs.h>
#import <arpa/inet.h>
#implementation IPChangeNotifier
-(id) initWithTimer:(float)time andDelegate:(id)del {
changeTimer = [NSTimer scheduleTimerWithTimeInterval:time target:self selector:#selector(checkForChange) userInfo:nil repeats:YES];
prevIP = #"";
changeDelegate = del;
}
-(void) checkForChange {
NSString *currentIP = [self getIPAddress];
if (![currentIP isEqualToString:prevIP]) {
if ([changeDelegate respondsToSelector:#selector(IPChangeDetected:)]){
[changeDelegate IPChangeDetected:currentIP previousIP:prevIP];
}
prevIP = currentIP;
}
}
- (NSString *)getIPAddress {
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
NSString *wifiAddress = nil;
NSString *cellAddress = nil;
// retrieve the current interfaces - returns 0 on success
if(!getifaddrs(&interfaces)) {
// Loop through linked list of interfaces
temp_addr = interfaces;
while(temp_addr != NULL) {
sa_family_t sa_type = temp_addr->ifa_addr->sa_family;
if(sa_type == AF_INET || sa_type == AF_INET6) {
NSString *name = [NSString stringWithUTF8String:temp_addr->ifa_name];
NSString *addr = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; // pdp_ip0
NSLog(#"NAME: \"%#\" addr: %#", name, addr); // see for yourself
if([name isEqualToString:#"en0"]) {
// Interface is the wifi connection on the iPhone
wifiAddress = addr;
} else
if([name isEqualToString:#"pdp_ip0"]) {
// Interface is the cell connection on the iPhone
cellAddress = addr;
}
}
temp_addr = temp_addr->ifa_next;
}
// Free memory
freeifaddrs(interfaces);
}
NSString *addr = wifiAddress ? wifiAddress : cellAddress;
return addr ? addr : #"0.0.0.0";
}
#end
You can then simply make whatever class you want a delegate by adding <IPChangeNotifierDelegate> to your interface file and then initialize the notifier by doing something simple like below.
IPChangeNotifier *ipChecker = [[IPChangeNotifier alloc] initWithTimer:1.0 andDelegate:self]
Also make sure you have the following method included to make sure you can get the change events and do whatever you need.
-(void) IPChangeDetected:(NSString*)newIP previousIP:(NSString*)oldIP {
// Do what you need
}
I'm writing a program which uses MapKit to display a map which will load custom annotations from a plist file. Each annotation is a dictionary item in the root array, with a title, subtitle, latitude, and longitude. When I hard-coded in the annotations for test purposes, the program worked beautifully. But with the addition of the MapDemoAnnotation class and my attempt to read in the property list, the program crashes upon launch.
Here is my annotation implementation:
#import "MapDemoAnnotation.h"
#implementation MapDemoAnnotation
#synthesize coordinate;
#synthesize title;
#synthesize subtitle;
-(id)initWithDictionary:(NSDictionary *)dict{
self = [super init];
if(self!=nil){
coordinate.latitude = [[dict objectForKey:#"latitude"] doubleValue];
coordinate.longitude = [[dict objectForKey:#"longitude"] doubleValue];
self.title = [dict objectForKey:#"name"];
self.subtitle = [dict objectForKey:#"desc"];
}
return self;
}
-(void)dealloc{
[title release];
[subtitle release];
[super dealloc];
}
#end
I'm guessing the viewDidLoad method in my RootViewController class is the problem, though.
- (void)viewDidLoad {
[super viewDidLoad];
MKMapView *mapView = (MKMapView*)self.view;
mapView.delegate = self;
mapView.mapType=MKMapTypeHybrid;
CLLocationCoordinate2D coordinate;
coordinate.latitude = 39.980283;
coordinate.longitude = -75.157568;
mapView.region = MKCoordinateRegionMakeWithDistance(coordinate, 2000, 2000);
//All the previous code worked fine, until I added the following...
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Locations" ofType:#"plist"];
NSData* data = [NSData dataWithContentsOfFile:plistPath];
NSMutableArray* array = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NSPropertyListXMLFormat_v1_0
errorDescription:nil];
if (array) {
NSMutableDictionary* myDict = [NSMutableDictionary dictionaryWithCapacity:[array count]];
for (NSDictionary* dict in array) {
MapDemoAnnotation* annotation = [[MapDemoAnnotation alloc]initWithDictionary:dict];
[mapView addAnnotation:annotation];
[annotation release];
}
NSLog(#"The count: %i", [myDict count]);
}
else {
NSLog(#"Plist does not exist");
}}
The program crashes for reasons I cannot figure, but I figure I must have done something wrong in reading in the property list or else in the MapDemoAnnotation class. Am I missing something obvious, or making a novice mistake?
My code is largely borrowed, so I could be way off base with how I'm approaching it.
Thanks in advance!
The third parameter in the call to propertyListFromData is wrong. The compiler must be giving you a "makes pointer from integer without a cast" warning there because the format parameter expects a pointer to a NSPropertyListFormat variable (so the method can return the format to you). So you need to do:
NSPropertyListFormat propertyListFormat;
NSMutableArray* array = [NSPropertyListSerialization
propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:&propertyListFormat
errorDescription:nil];
However, the documentation mentions that the above method is obsolete and you should use propertyListWithData:options:format:error: instead.
However, it's much easier to just call NSArray's initWithContentsOfFile: method instead:
NSString *plistPath = [[NSBundle mainBundle] pathForResource...
NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];
if (array) {
//your existing code here...
}
else {
NSLog(#"Plist does not exist");
}
[array release];
What follows is an initializer method. It creates a Movie structure from a file, with an eye to extracting the raw pixels for processing, as per Apple QA1443. This is then wrapped in a QTMovie – sourceMovie = [QTMovie movieWithQuickTimeMovie: ...] – for convenience.
After initializing such an object, the second method is called, and we attempt to use sourceMovie. However, it turns out that any attempt to access sourceMovie here results in EXC_BAD_ACCESS For instance, NSLog(#"%#", sourceMovie) is impossible. The movie appears to have been deallocated, although it is not clear why.
Furthermore, in this second method, the usual methods to obtain a CVPixelBufferRef do not properly function: QTVisualContextIsNewImageAvailable seems always to return NO, and QTVisualContextCopyImageForTime always gives you an imageBuffer pointing at 0x00. (I guess this is not surprising if the QTMovie, Movie or visualContext are somehow being deallocated.)
The question then is, why is sourceMovie inaccessible from the second method? Is it being deallocated as it seems? If so, why?
And now the code, and sorry in advance for the length.
// From the .h, we have the following inst var declarations:
Movie myMovie;
QTMovie *sourceMovie;
QTVisualContextRef visualContext;
CVPixelBufferRef imageBuffer;
pixels_xy sourceSize;
MovieAnalyzer *analyzer;
// And now to the #implementation...
-(id)initWithFileString:(NSString *)file {
if (self = [super init]) {
NSError *e;
// Bit of a hack - get the movie size using temporary QTMovie.
sourceMovie = [QTMovie movieWithFile:file error:&e];
if (e) {
[self release];
NSLog(#"Could not open movie.");
return nil;
}
NSSize movieSize = [[sourceMovie posterImage] size];
CGRect bounds = CGRectMake(0, 0, movieSize.width, movieSize.height);
// Save the size in pixels.
sourceSize.x = (int)movieSize.width, sourceSize.y = (int)movieSize.height;
CFStringRef movieLocation = (CFStringRef) file;
// Get a QT Visual Context, and create a movie inialized to use it for output.
visualContext = NULL;
OSStatus status = CreatePixelBufferContext(k32ARGBPixelFormat, &bounds, &visualContext);
if (noErr != status && NULL == visualContext) {
[self release];
NSLog(#"Problem initializing QT Visual Context.");
return nil;
}
/*** Instantiate the Movie ***/
myMovie = NULL;
Boolean trueValue = true;
QTNewMoviePropertyElement newMovieProperties[3] = {0};
// Setup movie location
newMovieProperties[0].propClass = kQTPropertyClass_DataLocation;
newMovieProperties[0].propID = kQTDataLocationPropertyID_CFStringPosixPath;
newMovieProperties[0].propValueSize = sizeof(CFStringRef);
newMovieProperties[0].propValueAddress = &movieLocation;
// Assign the visual context - could also be NULL
newMovieProperties[1].propClass = kQTPropertyClass_Context;
newMovieProperties[1].propID = kQTContextPropertyID_VisualContext;
newMovieProperties[1].propValueSize = sizeof(visualContext);
newMovieProperties[1].propValueAddress = &visualContext;
// Make the movie active
newMovieProperties[2].propClass = kQTPropertyClass_NewMovieProperty;
newMovieProperties[2].propID = kQTNewMoviePropertyID_Active;
newMovieProperties[2].propValueSize = sizeof(trueValue);
newMovieProperties[2].propValueAddress = &trueValue;
status = NewMovieFromProperties(3, newMovieProperties, 0, NULL, &myMovie);
if (status != noErr || myMovie == NULL) {
NSLog(#"Problem initializing theMovie"); // problem
[self release];
return nil;
}
// Create a new QTMovie with the Movie as its backing object
sourceMovie = [QTMovie movieWithQuickTimeMovie:myMovie disposeWhenDone:NO error:&e];
if (e) {
NSLog(#"Could not initialize QTMovie from Movie.");
[self release];
return nil;
}
[sourceMovie stepForward];
analyzer = [[MovieAnalyzer alloc] initWithColorString:"BGRA" andSourceSize:sourceSize];
}
return self;
}
-(NSImage*) supplyCalibrationImage {
NSLog(#"%x", &sourceMovie);
[sourceMovie stepForward]; // This fails!
....
}
[QTMovie movieWithQuickTimeMovie:disposeWhenDone:error:] is returning an autoreleased movie. If you want it to stick around past that one method, you need to retain it.