Setting multiple UNUserNotification firing only the last notification - objective-c

EDIT: I am setting exactly 365 local notifications UNUserNotification (one for each day a year). Button is calling at one time:
[self name1];
[self name2];
...
[self name365];
one name for every day. If I try only eg. 3 days, it works perfectly. If I call all days (365x), it fires only the last local notification (365. only) - day 1-364 is missed (not fired). Any ideas?
Code:
-(void)Name1{
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.hour = 9;
comps.minute = 0;
comps.day = 23;
comps.month = 10;
UNMutableNotificationContent *objNotificationContent = [[UNMutableNotificationContent alloc] init];
objNotificationContent.title = [NSString localizedUserNotificationStringForKey:#"NAME" arguments:nil];
objNotificationContent.body = [NSString localizedUserNotificationStringForKey:#"text"
arguments:nil];
objNotificationContent.sound = [UNNotificationSound soundNamed:#"notif_bobicek.mp3"];
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents: comps repeats:YES];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:#"requestNotificationForName1"
content:objNotificationContent trigger:trigger];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) { NSLog(#"Local Notification succeeded"); }
else { NSLog(#"Local Notification failed"); }}];
}
.
-(void)Name2{ ... // same code
-(void)Name365{... // same code
Note: Identifier is different for each scheduled local notification.

This does not answer your question directly and you really should parameterise your approach, but what I will show you can help a lot. I want to illustrate clearly what I meant with using #define in my comment.
Using #define is a powerful way to solve some tricky problems and even here it can make your life a lot easier. Think of #define as a type of search and replace, which it literally used to be, and here you can use that to define your message ONCE and then replace it 365 times in stead of creating 365 different messages. Here is an outline.
// MyClass.m
#import "MyClass.h"
// The \ indicates the macro continues on the next line
// Note this becomes just one long string without linebreaks so you can
// not use // to comment, you must use /* ... */ to comment
// The ## indicates it is a string concatenation
#define MYFUNC( DAY ) \
- ( void ) name ## DAY { \
/* Now you are inside nameDAY e.g. name1, name2 ... etc */ \
NSDateComponents *comps = [[NSDateComponents alloc] init]; \
comps.hour = 9; \
comps.minute = 0; \
comps.day = 23; \
comps.month = 10; \
/* Some examples below */ \
NSUInteger day = DAY; \
NSString * s = [NSString stringWithFormat:#"ID:%lu", DAY]; \
NSLog( #"Inside %#", s ); \
};
#implementation MyClass
// Now you can create them as below
MYFUNC( 1 )
MYFUNC( 2 )
MYFUNC( 3 )
MYFUNC( 4 )
// etc
// They are now defined and can be called as normal
- ( void ) test
{
[self name1];
[self name2];
[self name3];
// etc
}
#end
If you parameterise your approach but still need 365 functions you can e.g. expand the #define by adding more parameters. Anyhow, for more info see this really nice reference.
https://en.wikibooks.org/wiki/C_Programming/Preprocessor_directives_and_macros
HIH

Related

Change system time, time zone and auto checkbox in time and date settings programmatically

I'm trying to figure out how to edit the time and the 'Set Date and Time Automatically' check box programmatically. I've spent a while and cant find the solution.
I've tried looking at the NSUserDefault keys but don't see them.
NSLog(#"%#", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]);
help appreciated. This is OSX (not iphone).
This is not a complete answer. I just code below will just change the system time. Note: changing the system time requires root permission. Running the code via Xcode IDE as is will fail. Running from Terminal using sudo command works.
//
// main.m
// TimeChange
//
// Created by ... on 4/13/15.
// Copyright (c) 2015 .... All rights reserved.
//
#import <Foundation/Foundation.h>
#import <sys/time.h>
#include <errno.h>
extern int errno;
void NSLogTime(const struct tm *restrict temp, suseconds_t microseconds)
{
char tmbuf[64], buf[64];
strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", temp);
snprintf(buf, sizeof buf, "%s.%06d\n", tmbuf, microseconds);
NSLog(#" %#", [[NSString alloc] initWithUTF8String:buf]);
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
// Built from samples based on the URL listed below
// http://stackoverflow.com/questions/2408976/struct-timeval-to-printable-format
// http://www.linuxquestions.org/questions/programming-9/c-code-to-change-date-time-on-linux-707384/
// Do whatever you need to set the following variable
// In this example I am hard-coding it
int month = 2;
int day = 27;
int year = 2002;
NSLog(#"Getting current date/time...");
struct timeval currentTime;
int success = gettimeofday(&currentTime, 0); // should check for success
struct tm *localTime = localtime(&currentTime.tv_sec);
NSLogTime(localTime, currentTime.tv_usec);
if (localTime)
{
NSLog(#"...create new date/time structure...");
localTime->tm_mon = month - 1;
localTime->tm_mday = day;
localTime->tm_year = year - 1900;
const struct timeval tv = {mktime(localTime), 0};
success = settimeofday(&tv, 0);
// check if we are success
if (success == 0)
{
NSLog(#"...time was changed!");
// get the new time from the system and display it
struct timeval updatedTime;
gettimeofday(&updatedTime, 0); // should check for success
NSLogTime(localtime(&updatedTime.tv_sec), updatedTime.tv_usec);
}
else
{
// display the error message
NSLog(#"Error Setting Date: %s", strerror(errno));
}
}
}
return 0;
}
Below is screen shot of the coding running in the terminal.
Note: the one hour time difference in the output is because Daylight Saving Time (DST) was not in-effect back in Feb 22, 2002.
So I discovered that I could write an applescript that would execute bash script commands. Then I called the script with NSApplescript.
The cool thing is apple script has an elegant password dialog and it only needs to be handled once for everything. This is far nicer than making the terminal appear.
The downside was the process for calling the applescript with NSApplescript.
What should have been a simple process of passing 3 args to the script needed to be handled by about 50 lines of outdated NSAppleEvent code that didn't even work in Apples docs. Luckily, I found a post where someone knew the constants missing from the absent Carbon framework.
The Code:
// Caller responsible for well formed ip address.
+(BOOL)setDateAndTimePreferences:(NSString*)ipAddress setAutoNetworkTime:(BOOL)yNo withTimezone:(NSString*)timezone{
// Load the script from a resource by fetching its URL from within our bundle
// Note: if the script if stored in a nother file location, NSBundle may not be
// necessary. Make sure the path to the script is correct.
NSString* path = [[NSBundle mainBundle] pathForResource:#"date_time_pref" ofType:#"scpt"];
if (path != nil){
NSURL* url = [NSURL fileURLWithPath:path];
if (url != nil)
{
NSDictionary* errors = [NSDictionary dictionary];
NSAppleScript* appleScript =
[[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];
if (appleScript != nil)
{
// Get the value of the setAutoNetwork checkbox.
NSString *chkBox = (yNo == YES)? #"on": #"off";
// Create the arg parameters
NSAppleEventDescriptor* firstParameter =
[NSAppleEventDescriptor descriptorWithString:ipAddress];
NSAppleEventDescriptor* secondParameter =
[NSAppleEventDescriptor descriptorWithString:chkBox];
NSAppleEventDescriptor* thirdParameter =
[NSAppleEventDescriptor descriptorWithString:timezone];
// Create and populate the list of parameters.
NSAppleEventDescriptor* parameters = [NSAppleEventDescriptor listDescriptor];
[parameters insertDescriptor:firstParameter atIndex:1];
[parameters insertDescriptor:secondParameter atIndex:2];
[parameters insertDescriptor:thirdParameter atIndex:3];
// Create the AppleEvent target
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor* target = [NSAppleEventDescriptor
descriptorWithDescriptorType:typeProcessSerialNumber
bytes:&psn length:sizeof(ProcessSerialNumber)];
// We need these constants from the Carbon OpenScripting
// framework, but we don't actually need Carbon.framework.
#define kASAppleScriptSuite 'ascr'
#define kASSubroutineEvent 'psbr'
#define keyASSubroutineName 'snam'
// Create an NSAppleEventDescriptor with the script's method name to call,
// this is used for the script statement: "on set_preferences(arg1,arg2arg3)"
// Note that the routine name must be in lower case.
NSAppleEventDescriptor* handler =
[NSAppleEventDescriptor descriptorWithString:
[#"set_preferences" lowercaseString]];
// Create the event for an AppleScript subroutine,
// set the method name and the list of parameters
NSAppleEventDescriptor* event =
[NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:target
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
[event setParamDescriptor:handler forKeyword:keyASSubroutineName];
[event setParamDescriptor:parameters forKeyword:keyDirectObject];
// call the event in AppleScript
if (![appleScript executeAppleEvent:event error:&errors])
{
// report any errors from 'errors'
NSLog(#"Errors %#",[errors description]);
}
[appleScript release];
}
else{
// report any errors from 'errors'
NSLog(#"Error: applescript is nil");
}
}else{
NSLog(#"Could not locate the time_date_preferences script");
return NO;
}
}else{
NSLog(#"Could not locate the time_date_preferences script");
return NO;
}
return YES;
}
The Script:
on set_preferences(ipaddress, chkbox, timezone)
global timezonelist
do shell script "/usr/sbin/systemsetup -setusingnetworktime " & chkbox password "passwordhere" with administrator privileges
do shell script "/usr/sbin/systemsetup -setnetworktimeserver " & ipaddress with administrator privileges
set timezonelist to (do shell script "/usr/sbin/systemsetup -listtimezones" with administrator privileges)
if timezonelist contains timezone then
do shell script "/usr/sbin/systemsetup -settimezone " & timezone with administrator privileges
else
display notification "Please open Date and Time Preferences and set your time zone manually." with title ("Invalid Time Zone")
delay 1
end if
end set_preferences

How to use a run loop with NSTimer in Objective-C

I am writing a small program for printing to the console every few seconds.
The objective is to call a function on each of ten objects in an array every N seconds, where n is a class variable. I was wondering how I could incorporate such a timer loop into my code. Here is what I have. I would ver much appreciate a response. Thanks.
ALHuman.m
static NSInteger barkInterval = 3;
#implementation ALHuman
-(void)setMyDog:(ALDog *)dog{
myDog = dog;
}
-(ALDog *)getMyDog{
return myDog;
}
+(NSInteger)returnBarkInterval {
return barkInterval;
}
-(void)createDog{
ALDog *aDog = [[ALDog alloc]init];
char dogName [40] = " ";
NSLog(#"Please enter a name for %s's dog",[self name]);
scanf("%s",dogName);
[aDog setName:dogName];
char barkSound [40] = "";
NSLog(#"Please enter a bark sound for dog: %s",[aDog name]);
scanf("%s",barkSound);
[myDog setBarkSound:barkSound];
[myDog setCanBark:YES];
[self setMyDog:aDog];
}
-(void)callDog:(NSInteger)numberOfResponses {
NSLog(#"%s",[[self getMyDog] name]);
[[self getMyDog] bark:numberOfResponses];
}
-(NSInteger)getRandomNumberBetween:(NSInteger)from to:(NSInteger)to {
return (NSInteger)from + arc4random() % (to-from+1);
}
-(void)timerFireMethod:(NSTimer *)timer {
[self callDog:[self getRandomNumberBetween:1 to:5]];
}
#end
main.m
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSMutableArray *people = [[NSMutableArray alloc]init];
for (int i = 0; i < 10; i++) { // I didn't want to create a class method for creating these humans and their dogs, because it is unneccessary.
ALHuman *person = [[ALHuman alloc]init];
// NameGenerator *name = [[NameGenerator alloc]init]; I need to work on implementing this
[person setName:"Bob"];
[person createDog];
[person setHeight:[person getRandomNumberBetween:5 to:8]];
[people addObject:person];
}
NSLog(#"%#",people);
NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; //Here is where I am having trouble
for(ALHuman *human in people){
[NSTimer timerWithTimeInterval:[ALHuman returnBarkInterval] target:human selector:#selector(timerFireMethod:) userInfo:NULL repeats:YES];
}
return 0;
}
}
First, +[NSTimer timerWithTimeInterval:...] creates and returns a new timer object, but you're ignoring the return value. So, those timer objects are just lost and useless. You either want to manually schedule them into the run loop or use +scheduledTimerWithTimeInterval:... instead.
Second, you allow execution to flow to the return statement, which exits the main() function. When that happens, the process is terminated. It doesn't bother waiting for any timers to fire, or anything else for that matter.
If you want to wait and allow those timers to fire, you need to manually run the run loop (since you're not in the main thread of an application, which would run the run loop for you). You can invoke [myRunLoop run], [myRunLoop runUntilDate:someDate], or build a loop around an invocation of [myRunLoop runMode:someMode beforeDate:someDate]. It depends on under what circumstances you want the program to exit, if ever.
Use this simple runloop controller class.
(untested):
int main(int argc, const char * argv[])
{
#autoreleasepool {
RunLoopController *runLoopController = [RunLoopController new];
[runLoopController register];
NSMutableArray *people = [NSMutableArray new];
NSMutableArray *timers = [NSMutableArray new];
for (int i = 0; i < 10; i++) {
ALHuman *person = [[ALHuman alloc]init];
// NameGenerator *name = [[NameGenerator alloc]init]; I need to work on implementing this
[person setName:"Bob"];
[person createDog];
[person setHeight:[person getRandomNumberBetween:5 to:8]];
[people addObject:person];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:[ALHuman returnBarkInterval]
target:person
selector:#selector(timerFireMethod:)
userInfo:nil
repeats:YES];
[timers addObject:timer];
}
NSLog(#"%#",people);
while ([runLoopController run])
;
[runLoopController deregister];
}
}
However the issue you face is how to terminate the program when you are finished. You can either install a signal handler, or use some other metric to determine the program has finished, and then call [[RunLoopController mainRunLoopController] terminate].
The RunLoopController uses a simple signalling mechanism (a MACH port) in order to know that the runloop must terminate. Other usage examples exist on the github repo in the above link.

fetcherWithRequest:fetcherClass not found

I am getting a warning in my GTMHTTPUploadFetcher.m file that says "-fetcherWithRequest:fetcherClass" not found (return type defaults to "id")
for this code
+ (GTMHTTPUploadFetcher *)uploadFetcherWithRequest:(NSURLRequest *)request
fetcherService:(GTMHTTPFetcherService *)fetcherService {
// Internal utility method for instantiating fetchers
GTMHTTPUploadFetcher *fetcher;
if (fetcherService) {
fetcher = [fetcherService fetcherWithRequest:request
fetcherClass:self];
} else {
fetcher = (GTMHTTPUploadFetcher *) [self fetcherWithRequest:request];
}
return fetcher;
}
and then I get an error involving the Foundation Framework
Parse Issue
expected expression
//this is where the expected expression is
- (void)uploadNextChunkWithOffset:(NSUInteger)offset
fetcherProperties:(NSMutableDictionary *)props {
// upload another chunk
NSUInteger chunkSize = [self chunkSize];
NSString *rangeStr, *lengthStr;
NSData *chunkData;
NSUInteger dataLen = [self fullUploadLength];
if (offset == kQueryServerForOffset) {
// resuming, so we'll initially send an empty data block and wait for the
// server to tell us where the current offset really is
chunkData = [NSData data];
rangeStr = [NSString stringWithFormat:#"bytes */%lu", (unsigned long)dataLen];
lengthStr = #"0";
offset = 0;
} else {
// uploading the next data chunk
#if DEBUG
**//this is the exact line of code causing the problem//**
(unsigned long)NSAssert2(offset < dataLen, #"offset %lu exceeds data length %lu",
offset, dataLen);
#endif
NSUInteger thisChunkSize = chunkSize;
// if the chunk size is bigger than the remaining data, or else
// it's close enough in size to the remaining data that we'd rather
// avoid having a whole extra http fetch for the leftover bit, then make
// this chunk size exactly match the remaining data size
BOOL isChunkTooBig = (thisChunkSize + offset > dataLen);
BOOL isChunkAlmostBigEnough = (dataLen - offset < thisChunkSize + 2500);
if (isChunkTooBig || isChunkAlmostBigEnough) {
thisChunkSize = dataLen - offset;
}
chunkData = [self uploadSubdataWithOffset:offset
length:thisChunkSize];
rangeStr = [NSString stringWithFormat:#"bytes %lu-%u/%lu",
(unsigned long)offset, offset + thisChunkSize - 1, (unsigned long)dataLen];
lengthStr = [NSString stringWithFormat:#"%lu", (unsigned long)thisChunkSize];
}
//related to this
! expanded from macro 'NSAssert2'
#define NSAssert2(condition, desc, arg1, arg2) NSAssert((condition), (desc), (arg1), (arg2))
! expanded from macro 'NSAssert'
#if !defined(_NSAssertBody)
#define NSAssert(condition, desc, ...) \
do { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
if (!(condition)) { \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:self file:[NSString stringWithUTF8String:__FILE__] \
lineNumber:__LINE__ description:(desc), ##__VA_ARGS__]; \
} \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} while(0)
#endif
Only started getting the error after I updated Xcode (not to new version just update)
anyone have any suggestions not sure these two are related or not so will post this second part separately.
Solved this by going into time machine and resurrecting the old .m file and replacing it. It no doesn't give me an error, however I can't upload video because of MIME type problem, but that's another post.
Solved this by going into time machine and resurrecting the old .m file and replacing it.

Unknown errors in Xcode

I am following the instructions for a tutorial but I cannot figure out what is wrong. I have double checked everything. I put the the compiler errors in the code's comments below. Sorry, this will probably show how much of a noob I am.
// main.m
#import <Foundation/Foundation.h>
#import "LotteryEntry.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// Creates the date object
NSCalendarDate *now = [[NSCalendarDate alloc]init];
//Seed the random number generator
srandom(time(NULL));
NSMutableArray * array;
array = [[NSMutableArray alloc]init];
int i;
for (i = 0; i < 10; i++) {
//create a date/time object that is 'i' weeks from now
NSCalendarDate *iWeeksFromNow;
iWeeksFromNow = [now dateByAddingYears:0
months:0
days:(i * 7)
hours:0
minutes:0
second:0];
}
//create the LotteryEntry object
LotteryEntry *newEntry = [[LotteryEntry alloc]init];
[newEntry prepareRandomNumbers];
[newEntry setEntryDate: iWeeksFromNow];
//Error says "Use of undeclared identifier "iWeeksFromNow'. Did I not declare it above?
//add the lottery entry object to the array
[array addObject:newEntry];
}
for (LotteryEntry *entryToPrint in array) {
//Error says " Expected identifier or '('
//Display it's contents
NSLog(#"%#", entryToPrint);
}
[pool drain];
return 0;
//Error says " Expected identifier or '('
}
//Error says " Expected External declaration
You are declaring iWeeksFromNow inside a for loop, that's why the compiler doesn't consider it to exist outside
declare it outside, and assign values to it inside
You have an extra closing } as you call the -dateByAddingYears method.
First error : you declare iWeeksFromNew inside a for loop, thus it's unreachable from outside.
You have to declare before the beginning of the loop.
Second error : you have a bracket '}' after [array addObject:newEntry]; so the compiler thinks its the end of your method, remove it.
That should fix all other error you have
First, iWeeksFromNow is declared within the scope of a for loop, so it will be visible only within that loop. Second, as pointed out by Black Frog, you have an extra closing parenthesis.
Move the declaration out that loop block. You've got a scope problem here: The iWeeksFromNew only exists within the loop
NSCalendarDate *iWeeksFromNow;
int i;
for (i = 0; i < 10; i++) {
//create a date/time object that is 'i' weeks from now
iWeeksFromNow = [now dateByAddingYears:0
months:0
days:(i * 7)
hours:0
minutes:0
second:0];
}

About the fate of malloc()ed arrays of arrays

my first question on Stackoverflow.
Let me start with a bit of code. It's a bit repetitive so I'm going to cut out the parts I repeat for different arrays (feel free to ask for the others). However, please ignore the code in preference to answering the Qs at the bottom. Firstly: thank you to answerers in advance. Secondly: the freeing of data.
#implementation ES1Renderer
GLfloat **helixVertices;
GLushort **helixIndices;
GLubyte **helixColors;
- (void)freeEverything
{
if (helixVertices != NULL)
{
for (int i=0; i < alphasToFree / 30 + 1; i++)
free(helixVertices[i]);
free(helixVertices);
}
if (helixIndices != NULL)
{
for (int i=0; i < alphasToFree / 30 + 1; i++)
free(helixIndices[i]);
free(helixIndices);
}
if (helixColors != NULL)
{
for (int i=0; i < alphasToFree / 30 + 1; i++)
free(helixColors[i]);
free(helixColors);
}
}
(I will get to the calling of this in a moment). Now for where I malloc() the arrays.
- (void)askForVertexInformation
{
int nrows = self.helper.numberOfAtoms / 300;
int mrows = [self.helper.bonds count] / 300;
int alphaCarbonRows = [self.helper.alphaCarbons count] / 30;
helixVertices = malloc(alphaCarbonRows * sizeof(GLfloat *) + 1);
helixIndices = malloc(alphaCarbonRows * sizeof(GLfloat *) + 1);
helixColors = malloc(alphaCarbonRows * sizeof(GLfloat *) + 1);
for (int i=0; i < alphaCarbonRows + 1; i++)
{
helixVertices[i] = malloc(sizeof(helixVertices) * HELIX_VERTEX_COUNT * 3 * 33);
helixIndices[i] = malloc(sizeof(helixIndices) * HELIX_INDEX_COUNT * 2 * 3 * 33);
helixColors[i] = malloc(sizeof(helixColors) * HELIX_VERTEX_COUNT * 4 * 33);
}
[self.helper recolourVerticesInAtomRange:NSMakeRange(0, [self.helper.alphaCarbons count]) withColouringType:CMolColouringTypeCartoonBlue forMasterColorArray:helixColors forNumberOfVertices:HELIX_VERTEX_COUNT difference:30];
self.atomsToFree = self.helper.numberOfAtoms;
self.bondsToFree = [self.helper.bonds count];
self.alphasToFree = [self.helper.alphaCarbons count];
}
Finally, the bit which calls everything (this is a separate class.)
- (void)loadPDB:(NSString *)pdbToLoad
{
if (!self.loading)
{
[self performSelectorOnMainThread:#selector(stopAnimation) withObject:nil waitUntilDone:YES];
[self.renderer freeEverything];
[renderer release];
ES1Renderer *newRenderer = [[ES1Renderer alloc] init];
renderer = [newRenderer retain];
[self performSelectorOnMainThread:#selector(stopAnimation) withObject:nil waitUntilDone:YES]; // need to stop the new renderer animating too!
[self.renderer setDelegate:self];
[self.renderer setupCamera];
self.renderer.pdb = nil;
[renderer resizeFromLayer:(CAEAGLLayer*)self.layer];
[newRenderer release];
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(setup:) object:pdbToLoad];
[self.queue addOperation:invocationOperation];
[invocationOperation release];
}
}
- (void)setup:(NSString *)pdbToLoad
{
self.loading = YES;
[helper release];
[renderer.helper release];
PDBHelper *aHelper = [[PDBHelper alloc] initWithContentsOfFile:pdbToLoad];
helper = [aHelper retain];
renderer.helper = [aHelper retain];
[aHelper release];
if (!resized)
{
[self.helper resizeVertices:11];
resized = YES;
}
self.renderer.helper = self.helper;
[self.helper setUpAtoms];
[self.helper setUpBonds];
if (self.helper.numberOfAtoms > 0)
[self.renderer askForVertexInformation];
else
{
// LOG ME PLEASE.
}
[self performSelectorOnMainThread:#selector(removeProgressBar) withObject:nil waitUntilDone:YES];
[self performSelectorOnMainThread:#selector(startAnimation) withObject:nil waitUntilDone:YES];
self.renderer.pdb = pdbToLoad;
self.loading = NO;
}
What I'm doing here is loading a molecule from a PDB file into memory and displaying it on an OpenGL view window. The second time I load a molecule (which will run loadPDB: above) I get the Giant Triangle Syndrome and Related Effects... I will see large triangles over my molecule.
However, I am releasing and reallocating my PDBHelper and ES1Renderer every time I load a new molecule. Hence I was wondering:
1. whether the helixVertices, helixIndices and helixColors which I have declared as class-wide variables are actually re-used in this instance. Do they point to the same objects?
2. Should I be setting all my variables to NULL after freeing? I plan to do this anyway, to pick up any bugs by getting a segfault, but haven't got round to incorporating it.
3. Am I even right to malloc() a class variable? Is there a better way of achieving this? I have no other known way of giving this information to the renderer otherwise.
I can't answer your general questions. There's too much stuff in there. However, this caught my eye:
[helper release];
[renderer.helper release];
PDBHelper *aHelper = [[PDBHelper alloc] initWithContentsOfFile:pdbToLoad];
helper = [aHelper retain];
renderer.helper = [aHelper retain];
[aHelper release];
I think this stuff possibly leaks. It doesn't make sense anyway.
If renderer.helper is a retain or copy property, do not release it. It already has code that releases old values when it is assigned new values. Also do not retain objects you assign to it.
You have alloc'd aHelper, so there's no need to retain it again. The above code should be rewritten something like:
[helper release];
helper = [[PDBHelper alloc] initWithContentsOfFile:pdbToLoad];
renderer.helper = helper;
Also, I think your helix malloced arrays should probably be instance variables. As things stand, if you have more than one ES1Renderer, they are sharing those variables.