Declare Returning an Object

I would like to write a declare for an iOS function that returns an Objective C object. I assume this comes back as a pointer, but how to I get at its properties.

Further, eventually I need to receive an array of objects.

I’ve been looking at various examples, but have still not figured this out. I don’t think I’m completely useless; I have several apps in the iPhone app store written in Objective-C.

-Bob Gordon

Maybe post which objects you are using so one of us can help?

It is also possible that I have already implemented what you are looking for in iOSKit:
https://github.com/kingj5/iOSKit

Jason

Please post the class name and the selector name. Without these details it is impossible to help.

Thank you for the quick response!

In particular I’m interested in MPMediaQuery.
MPMediaQuery.songsQuery() and MPMediaQuery.albumsQuery(), these appear to be class methods form which on can obtain (eventually) an array of MPMediaItems.

Ideally I would like to work this out by myself as much as possible as I think it would be a good kind of thing to know. So hints and suggestions rather than a solution would be my preference.

-Bob

Well, Declare Maker was able to successfully parse the class into Xojo code if you want it, but here are a few hints:

for the methods songsQuery and albumsQuery that you want, you will need to use NSClassFromString to get the class reference, then you can call the class functions.
You would do it like this:

declare function NSClassFromString lib "Foundation.framework" (clsName as CFStringRef) as Ptr

This gives you a pointer to the obj-C class like you could use directly in Obj-C. Since it is a flat C declare you do not need to use a selector in it.
For the class function you will do:

declare function songsQuery lib "MediaPlayer.framework" selector "songsQuery" (clsRef as Ptr) as ptr

This declare is slightly different since you have to use a selector since all class and instance methods are selectors in Obj-C. If you wanted to create a declare for the albumsQuery you would just have to change the selector in quotes. These selectors can be found directly in the apple docs, and must include any colons which are present there in your declare.

Now that you have these two (or more) declares, you can string them together to get the object back.

First we get the class reference

dim MPMediaQueryClass as Ptr = NSClassFromString("MPMediaQuery")
Then we get the songs query:

dim songs_Query as Ptr = songsQuery(MPMediaQueryClass)
Then you can use this object with further declares to get your NSArray of MPMediaItems.

Altogether the code for this would be:

declare function NSClassFromString lib "Foundation.framework" (clsName as CFStringRef) as Ptr declare function songsQuery lib "MediaPlayer.framework" selector "songsQuery" (clsRef as Ptr) as ptr dim MPMediaQueryClass as Ptr = NSClassFromString("MPMediaQuery") dim songs_Query as Ptr = songsQuery(MPMediaQueryClass)

Note that I haven’t actually tested this, I’ve just written it up in the forum, but it should work.

If you have more questions, just ask.
Jason

To expand on that, you will need to read the items property of the MPMediaQuery. This is done with a simple selector of just the property name (this is always true for reading a variable, unless it is a boolean and has a special getter). So to access the items property you will do:

declare function items lib "MediaPlayer.framework" selector "items" (obj_id as ptr) as ptr dim itemsNSArray as ptr = items(songs_Query)

Then you can write other declares to iterate through the NSArray, or you can grab iOSKit which has NSArray implemented as a Xojo object for you.

[code]Declare Function NSClassFromString Lib “Foundation” (className as CFStringRef) as Ptr
Declare Function songsQuery Lib “MediaPlayer” Selector “songsQuery” (MPMediaQueryClass As Ptr) As Ptr
Declare Function items Lib “MediaPlayer” Selector “items” (MPMediaQuery As Ptr) As Ptr
Declare Function count Lib “Foundation” Selector “count” (NSArray As Ptr) As Integer
Declare Function objectAtIndex Lib “Foundation” Selector “objectAtIndex:” (NSArray As Ptr, idx As Integer) As Ptr
Declare Function valueForProperty Lib “MediaPlayer” Selector “valueForProperty:” (MPMediaItemPtr As Ptr, prop As Ptr) As Ptr
Declare Function CFBundleGetBundleWithIdentifier Lib “CoreFoundation” (bundleID As CFStringRef) As Ptr
Declare Function CFBundleGetDataPointerForName Lib “CoreFoundation” (bundle As Ptr, symbolName As CFStringRef) As Ptr
Declare Function UTF8String Lib “Foundation” Selector “UTF8String” (NSString As Ptr) As CString

Dim bundlePtr As Ptr = CFBundleGetBundleWithIdentifier(“com.apple.MediaPlayer”)
Dim albumTitlePointer As Ptr = CFBundleGetDataPointerForName(bundlePtr, “MPMediaItemPropertyAlbumTitle”).Ptr(0)

Dim songsQueryPtr As Ptr = songsQuery(NSClassFromString(“MPMediaQuery”))
Dim itemsArrayPtr As Ptr = items(songsQueryPtr)
Dim count As Integer = count(itemsArrayPtr)
For i As Integer = 0 To count - 1
Dim mediaItemPtr As Ptr = objectAtIndex(itemsArrayPtr, i)
Dim albumTitlePtr As Ptr = valueForProperty(mediaItemPtr, albumTitlePointer)
Dim albumTitle As CString = UTF8String(albumTitlePtr)
Next[/code]

… same here!

[quote=247379:@Eli Ott][code]Declare Function NSClassFromString Lib “Cocoa” (className as CFStringRef) as Ptr
Declare Function songsQuery Lib “MediaPlayer” Selector “songsQuery” (MPMediaQueryClass As Ptr)
Declare Function items Lib “MediaPlayer” Selector “items” (MPMediaQuery As Ptr)
Declare Function count Lib “Cocoa” Selector “count” (NSArray As Ptr) As Integer)
Declare Function objectAtIndex Lib “Cocoa” Selector “objectAtIndex:” (NSArray As Ptr, idx As Integer) As Ptr
Declare Function valueForProperty Lib “” Selector “valueForProperty:” (MPMediaItemPtr As Ptr, prop As CFStringRef) As Ptr
Declare Function CFBundleGetBundleWithIdentifier Lib “CoreFoundation” (bundleID As CFStringRef) As Ptr
Declare Function CFBundleGetDataPointerForName Lib “CoreFoundation” (bundle As Ptr, symbolName As CFStringRef) As Ptr
Declare Function UTF8String Lib “Foundation” Selector “UTF8String” (NSString As Ptr) As CString

Dim bundlePtr As Ptr = CFBundleGetBundleWithIdentifier(“com.apple.MediaPlayer”)
Dim albumTitle As Ptr = CFBundleGetDataPointerForName(bundlePtr, “MPMediaItemPropertyAlbumTitle”).Ptr(0)

Dim songsQueryPtr As Ptr = songsQuery(NSClassFromString(“MPMediaQuery”))
Dim itemsArrayPtr As Ptr = items(songsQueryPtr)
Dim count As Integer = count(itemsArrayPtr)
For i As Integer = 0 To count - 1
Dim mediaItemPtr As Ptr = objectAtIndex(itemsArrayPtr, i)
Dim albumTitlePtr As Ptr = valueForProperty(mediaItemPtr, albumTitle)
Dim albumTitle As String = UTF8String(albumTitlePtr)
Next[/code]

… same here![/quote]
You will have some problems with this code since Cocoa doesn’t exist on iOS (you’ll get a linker error) and you must specify a framework for all declares.

Corrected these.

Much thanks. I will by trying this out (probably tomorrow AM).

I just tested this on my phone, and it worked. My next goal is to be sure I understand what’s going on.

Before testing I wrote a little logging utility so I can write messages to a text file and then display them on the phone from inside the app. Would anyone else be interested in such a thing?

Thank you again.

I need to share this with someone!

Just wrote a function with a declare (and some other stuff elsewhere) that gets the album artwork from iTunes, which is eventually shown in a table view.

Worked the first time (nothing works the first time). I may be getting the hang of this. (Crashes are coming, I’m sure.)

Anyway, some progress.