2

I am trying to write a category over iTunesTrack with associated objects (an NSMutableDictionary and an NSNumber)

#import "iTunes.h"
#import <objc/runtime.h>

@interface iTunesTrack (dictionary)
- (NSMutableDictionary*) getDictionary;
- (NSNumber*) getScan;
- (BOOL)scanTrack:(NSString *)equationString;
@end

This fails:

Undefined symbols for architecture x86_64:
  "_OBJC_CLASS_$_iTunesTrack", referenced from:
      l_OBJC_$_CATEGORY_iTunesTrack_$_dictionary in iTunesTrack+dictionary.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I have double checked that the Scripting Bridge framework is added and that the iTunesTrack+dictionary.m file is attached to the target. Could this be some error with combining Categories with Scripting Bridge?


Update:

If I replace iTunesTrack with SBObject, this works. I have no idea why, though.


Update 2:

This problem is reproducible:

  1. Create new project
  2. Add Scripting Bridge Framework and the iTunes.h header file.
  3. Create new category of iTunesTrack with an arbitrary name
  4. Ensure that iTunesTrack+name.h imports iTunes.h
  5. Build

I found this page which describes using NSProxy and NSCache to store iTunesTrack objects. Would this be a better solution than trying to make a category?

abroekhof
  • 796
  • 1
  • 7
  • 20

4 Answers4

1

Scripting Bridge is quite a mess.

The class iTunesTrack is actually called ITunesTrack under the hood.
I think they were not quite consistent with the leading lowercase i.

This is why they changed it after a while, but probably did not want to do it in the header file, to not change their API.

I don't think there is a way to fix this.

You can, however, just create the category on SBObject.

// The interface can be declared as iTunesTrack
@interface iTunesTrack (Additions)
...
@end

// The category MUST be implemented on SBObject
@implementation SBObject (Additions)
...
@end

Caution

Be aware that the category will be available on every SBObject, so make sure that all properties and methods have a unique interface.

IluTov
  • 6,807
  • 6
  • 41
  • 103
  • NSAddict's answer pointed the way to do something I've always wanted: implement - (id)debugQuickLookObject; for SBObject classes. – Ron Reuter Mar 19 '16 at 03:10
1

You can't put a category on iTunesTrack (or ITunesTrack, or whatever it's called in your header) because that requires the class to exist at link time, and it doesn't: Scripting Bridge creates the target application's classes dynamically at runtime. (And they have technically arbitrary names, which is why -classForScriptingClass exists.) It's still possible to add a method to the generated class, but it means mucking about with the runtime, which is generally more trouble than it's worth. Just put your category method on SBObject and try to be careful.

Chris N
  • 905
  • 5
  • 10
0

NSAddict's answer pointed the way to do something I've always wanted: implementing debugQuickLookObject for SBObject types to make debugging easier. Here's the category that does iTunesTrack and iTunesArtwork.

//  SBObject+Extensions.h

@import ScriptingBridge;

@interface SBObject (Extensions)

- (id)debugQuickLookObject;

@end


//  SBObject+Extensions.m

#import "iTunes.h"

@implementation SBObject (Extensions)

- (id)debugQuickLookObject
{
    NSString *className = self.className;

    if ([className isEqualToString:@"ITunesTrack"])
    {
        return [self handleITunesTrack];
    }
    else if ([className isEqualToString:@"ITunesArtwork"])
    {
        return [self handleITunesArtwork];
    }

    return [self description];
}

- (NSString*)handleITunesTrack
{
    iTunesTrack *track = (iTunesTrack *)self;

    NSMutableString *s = [NSMutableString new];

    [s appendFormat:@"Title:    %@\n", track.name];
    [s appendFormat:@"Artist:   %@\n", track.artist];
    [s appendFormat:@"Album:    %@\n", track.album];
    [s appendFormat:@"Duration: %f seconds\n", track.duration];

    return s;
}

- (NSImage*)handleITunesArtwork
{
    iTunesArtwork *artwork = (iTunesArtwork *)self;

    NSData *data   = [artwork rawData];
    NSImage *image = [[NSImage alloc] initWithData:data];

    return image;
}

@end
Ron Reuter
  • 1,287
  • 1
  • 8
  • 14
-2

You may find the answer in this discussion: linker command failed with exit code 1 (use -v to see invocation)

Also you can try to clean and then rebuild your project or go to Project -> Build Settings -> Valid Architectures and check whether there's all correct. Some of these advises may help you.

Community
  • 1
  • 1
Miroslav
  • 546
  • 2
  • 9
  • 22
  • I've tried cleaning. I also just tried making a brand new project with only the category, iTunes.h and Scripting Bridge added and it still fails. – abroekhof May 06 '13 at 15:11