PDA

View Full Version : Objective-C Problems


King Kovifor
2008-01-22, 19:02
Hey,

This is a thread that is in conjunction with this (http://forums.applenova.com/showthread.php?t=27910) thread. Now I am trying to accomplish the following things in Objective-C using scripting bridge. Now I cannot figure this out. So I will go through a list...


My application, Tune-A-Holic (TAH), will stall if iTunes is quit before the application since it depends on iTunes. I would like to be able to keep TAH open while iTunes is not running so that it can be a remote start for users who want that to happen.
If iTunes is open, but it is not actually playing a song, TAH will crash and stall because it attempts to fetch the current song. Is there a way within Scripting Bridge to check to make sure it is playing a song (with one in currentTrack) so that I could make a different menu bar item so that it doesn't stall and crash?
How do I use images within my menu bar item, and how tall should they be so they don't mess with my NSMenuItem's height?
While using an NSMenuItem, how can I make one a selected one? Like using a check mark?
In conjunction with the last question, how can when a new choice is made I can call a function to make the changes and save the change?

That is all I can think about right now. I am sure I will think of some more by the time I finish this version!

MCQ
2008-01-22, 21:14
My application, Tune-A-Holic (TAH), will stall if iTunes is quit before the application since it depends on iTunes. I would like to be able to keep TAH open while iTunes is not running so that it can be a remote start for users who want that to happen.



Would this help?

http://developer.apple.com/releasenotes/ScriptingAutomation/RN-ScriptingBridge/index.html#//apple_ref/doc/uid/TP40004741-DontLinkElementID_7



If iTunes is open, but it is not actually playing a song, TAH will crash and stall because it attempts to fetch the current song. Is there a way within Scripting Bridge to check to make sure it is playing a song (with one in currentTrack) so that I could make a different menu bar item so that it doesn't stall and crash?



Two guesses - try checking the playerState first before trying to get currentTrack


typedef enum {
iTunesEPlSStopped = 'kPSS',
iTunesEPlSPlaying = 'kPSP',
iTunesEPlSPaused = 'kPSp',
iTunesEPlSFastForwarding = 'kPSF',
iTunesEPlSRewinding = 'kPSR'
} iTunesEPlS;

@property (readonly) iTunesEPlS playerState; // is iTunes stopped, paused, or playing?


Alternatively - after trying to call currentTrack, check if the returned object exists before trying to access its properties.

King Kovifor
2008-01-23, 15:27
Would this help?

http://developer.apple.com/releasenotes/ScriptingAutomation/RN-ScriptingBridge/index.html#//apple_ref/doc/uid/TP40004741-DontLinkElementID_7



Two guesses - try checking the playerState first before trying to get currentTrack


typedef enum {
iTunesEPlSStopped = 'kPSS',
iTunesEPlSPlaying = 'kPSP',
iTunesEPlSPaused = 'kPSp',
iTunesEPlSFastForwarding = 'kPSF',
iTunesEPlSRewinding = 'kPSR'
} iTunesEPlS;

@property (readonly) iTunesEPlS playerState; // is iTunes stopped, paused, or playing?


Alternatively - after trying to call currentTrack, check if the returned object exists before trying to access its properties.

The first one didn't help.

But if iTunes playing state, what would be the state for not playing any thing? Or have something paused. Maybe use [iTunes playpause]; twice? So that it automatically plays and pauses if it wasn't playing anything or it will pause and start playing if it is already playing?

MCQ
2008-01-23, 18:44
The first one didn't help.

But if iTunes playing state, what would be the state for not playing any thing?


I assume --> iTunesEPlSStopped = 'kPSS'

So, I'm guessing something along the lines of the following in your Init or awakeFromNib:


iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];

iTunesEPlS state = [iTunes playerState];

if (state == iTunesEPlSStopped)
{
// Don't try to call/manipulate information about current track
}
else
{
// Do the current track manipulation here
}

King Kovifor
2008-01-23, 18:55
Thanks. That seems helpful into what I am doing...

King Kovifor
2008-01-27, 16:20
Ok. I am getting errors and this code is not allowing me to open the menu bar:

if([[iTunes playerState] isEqualToString:@"kPSS"])
{
[ten setTitle:@"Play Current Song"];
}
else if([[iTunes playerState] isEqualToString:@"kPSp"])
{
[ten setTitle:@"Play Current Song"];
}
else
{
[ten setTitle:@"Pause Current Song"];
}

There error is invalid type iTunesEPlS.... help would be appreciated.

ShadowOfGed
2008-01-27, 22:04
Your errors are because that enumeration is an integer value. Though it looks like a string, anything with single quotes becomes an integer constant. On both 32- and 64-bit systems (using the scheme employed by Apple), an int is 32 bits. Thus, you can actually stuff a 4-character constant into an integer.

So, your code should actually look like:

switch ([iTunes playerState])
{
case iTunesEPlSStopped:
[ten setTitle:@"Play Current Song"];
break;

case iTunesEPlSPaused:
[ten setTitle:@"Play Current Song"];
break;

case iTunesEPlSPlaying:
[ten setTitle:@"Pause Current Song"];
break;

default:
break;
}

As an aside, the ability to stuff 4-character "string" constants inside integers is why type and creator codes are always 4 characters; it's much faster than comparing huge quantities of strings, since all you're interested in is character-for-character equality.

billybobsky
2008-01-28, 02:04
Hmm...

This is unrelated but...

So I have just finished my cocoa-python application, which involved some trickery to get a drawer to open and close since i had no idea how get the instance of nsdrawer being used without having it send back to its delegate its id when it was about to be open. regardless, i don't for the moment, care about the proper method since it works... well, kind of...

i only really have a working knowledge of python and if it weren't for the massive amounts of cocoa reading i did in the last week, i wouldn't be able to tell you what a random slice of c is doing as opposed to not doing.

regardless, i cannot get my application to properly compile for the 10.4u sdk. It gives me an error about being unable to find the fast enumeration (enumerationMutation) C 2.0 method. i suspect that this is due to the fact that i am using the PyobjC 2.0 bridge on leopard as my development environment. I don't really want to downgrade everything to avoid losing 10.4u functionality, is there any other way to avoid this issue?

My program makes use of for loops, and while i can change them to while loops (i guess) i don't want to...

ShadowOfGed
2008-01-28, 09:21
If you're using any scripting bridge technologies, like PyObjC, you're forced to use 10.5 or newer. Those features are new in Leopard.

Also, the FastEnumeration protocol is new in Objective-C 2.0, which is also a Leopard-only feature. So you simply can't use any of these technologies under Tiger, which is why trying to compile against the 10.4u SDK fails.

billybobsky
2008-01-28, 11:43
actually... PyObjC existed well before 10.5... There are stable releases for the last two OSs as well, and apple has a developer tutorial dating back to pre-leopard...

Really, all I want is a button in xcode to tell it NOT to use fast enumeration...

ShadowOfGed
2008-01-28, 11:55
actually... PyObjC existed well before 10.5... There are stable releases for the last two OSs as well, and apple has a developer tutorial dating back to pre-leopard...

Really, all I want is a button in xcode to tell it NOT to use fast enumeration...

Yes, Python bindings for Objective-C did exist prior to 10.5, but PyObjC was overhauled in 10.5 to utilize the scripting bridge technologies (and not static bindings). I have no idea if there's a way to disable the use of the FastEnumeration for bound Objective-C collections. (Or is a Python collection trying to implement the FastEnumeration protocol so you can pass Python collections into Objective-C?)

I'm not really sure how to solve your problem at the moment. :\

King Kovifor
2008-01-28, 16:05
Thanks for that help. :)

billybobsky
2008-01-28, 20:42
Yes, Python bindings for Objective-C did exist prior to 10.5, but PyObjC was overhauled in 10.5 to utilize the scripting bridge technologies (and not static bindings). I have no idea if there's a way to disable the use of the FastEnumeration for bound Objective-C collections. (Or is a Python collection trying to implement the FastEnumeration protocol so you can pass Python collections into Objective-C?)

I'm not really sure how to solve your problem at the moment. :\
You know I might have an additional bit of info needed...

I tried running the program on another leopard machine and it crashed before starting up, it seems that the pyobjc libraries aren't getting built into the program and since they natively DON'T exist on Leopard (which is in direct conflict with everything out there), the program couldn't run.

Is there a way to get xcode to compile the called (non-system) modules/libraries with the code?

thanks...

ShadowOfGed
2008-01-28, 20:57
What you're referring to is called static linking.

However, I think that requires that the libraries you use are available as a static library instead of the dynamic libraries employed by Frameworks and BSD-style dylibs.

As a question to help us understand your problem, are you using Python for all your high-level logic and simply looking to use Objective-C classes? Or have you written some Python classes you'd like to access from within Objective-C?

billybobsky
2008-01-28, 23:41
Python logic calling objective-c...

The program works on every leopard-running mac i install pyobjc 2.0.

It is irritating that all I have effectively done is create a nice gui interface that requires the user to install the finicky pyobjc...

I wanted this program to be self-contained, completely so...