How to get the file item right-clicked in Finder on OSX - objective-c

I'm writing a plugin via mach_inject to add an item to Finder context menu. I have successfully add it by hooking NSMenu. But now i need to get the item that is right-clicked.
Someone said we could use the following code, but it can only get the selected items instead of right-clicked item (They are different!!!! In Finder, if you select one item and right-clicked another item, the selected one won't change). Anyone knows how to get right-click item in Finder? Thanks!
SBElementArray * selection = [[finder selection] get];
NSArray * items = [selection arrayByApplyingSelector:#selector(URL)];
for (NSString * item in items) {
NSURL * url = [NSURL URLWithString:item];
NSLog(#"selected item url: %#", url);
}

Before get the selected files, you should prepare some help code
struct TFENode {
struct OpaqueNodeRef *fNodeRef;
};
struct TFENodeVector {
struct TFENode *_begin;
struct TFENode *_end;
struct TFENode *_end_cap;
};
- (NSArray *)arrayForNodeVector:(const struct TFENodeVector *)vector
{
NSInteger capacity = vector->_end - vector->_begin;
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:capacity];
struct TFENode *node;
for (node = vector->_begin; node < vector->_end; ++node) {
[array addObject: [self pathForNode:node]];
}
return array;
}
You can get files like this
// Snow Leopard & Lion
// gNodeHelper is where you put above code
// override_handleContextMenuCommon: is your override function
+ (void)override_handleContextMenuCommon:(unsigned int)context
nodes:(const struct TFENodeVector *)nodes
event:(id)event
view:(id)view
windowController:(id)windowController
addPlugIns:(BOOL)flag
{
NSArray *paths = [gNodeHelper arrayForNodeVector:nodes];
[self override_handleContextMenuCommon:context
nodes:nodes
event:event
view:view
windowController:windowController
addPlugIns:flag];
}

Related

How to parse and take only this string value

I wanted to get only array string value app. As example(SLGoogleAuth ,HalfTunes,TheBackgrounder,Calculiator) . But don't know how to do?
It's a code.
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSLog(#"apps: %#", [workspace performSelector:selectorALL]);
}
It's output:
Thanks in advance
You do not want to parse that. NSLog prints out a description of an object. You want to access that value directly.
[LSApplicationWorkspace allApplications];
returns NSArray of LSApplicationProxy. LSApplicationProxy class has a ivar _bundleURL that contains information that you need. You need runtime functions to access it. Working example below:
// #import <objc/runtime.h>
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSArray* appProxies = [workspace performSelector:selectorALL];
Ivar bundleUrlIvar = class_getInstanceVariable([appProxies.firstObject class], "_bundleURL");
NSMutableString* result = [NSMutableString string];
for (id appProxy in appProxies)
{
NSURL* url = object_getIvar(appProxy, bundleUrlIvar);
// at this point you have the information and you can do whatever you want with it
// I will make it a list as you asked
if (url)
{
[result appendFormat:#",%#", [url lastPathComponent]];
}
}
if (result.length > 0)
{
// remove comma from beginning of the list
[result deleteCharactersInRange:NSMakeRange(0, 1)];
}
NSLog(#"apps: %#", result);
Note that this will be rejected by AppStore as you are using private apis. So use at your own discretion.

Swift's "if let" equivalent in Objective C

What would be "if let" equivalent in Objective C? The example snippet I want to convert to Objective C is below;
if let pfobjects = images as? [PFObject] {
if pfobjects.count > 0 {
var imageView: PFImageView = PFImageView()
imageView.file = pfobjects[0] as! PFFile
imageView.loadInBackground()
}
}
There's no direct equivalent to if let in Objective-C, because if let does Swift-specific things (unwrapping optionals and rebinding identifiers) that don't have direct equivalents in Objective-C.
Here's a nearly equivalent of your Swift code:
if (images != nil) {
NSArray<PFObject *> *pfobjects = (id)images;
if (pfobjects.count > 0) {
PFImageView *imageView = [[PFImageView alloc] init];
assert([pfobjects[0] isKindOfClass:[PFFile class]]);
imageView.file = (PFFile *)pfobjects[0];
[imageView loadInBackground];
}
}
But this Objective-C code won't verify that images only contains instances of PFObject, and should successfully create an image view as long as pfobjects[0] is a PFFile. Your Swift code will do nothing (create no image view) if images contains any non-PFObject elements.
You can use NSPredicate to verify the array contains only instances of PFObject:
NSPredicate *p = [NSPredicate predicateWithFormat:#"self isKindOfClass: %#", [PFObject class]];
NSInteger numberThatArePFObjects = [images filteredArrayUsingPredicate:p].count;
if(numberThatArePFObjects && numberThatArePFObjects == images.count){
// certain that images only contains instances of PFObject.
}
If however you weren't working with an array but a single object then it is simpler:
if([image isKindOfClass:[PFObject class]]){
// certain that image is a valid PFObject.
}
Or if you wanted a new variable:
PFObject* obj = nil;
if([image isKindOfClass:[PFObject class]] && (obj = image)){
// certain that obj is a valid PFObject.
}
You can use something like this:
NSArray<PFObject *> *pfobjects;
if ([images isKindOfClass: [NSArray<PFObject> class]] && (pfobjects = images)) {
// your code here
}
You want three things simultaneously. Let's split them:
variable as? OtherType is possible, but erases type, because it returns id. Implementation is as easy as a category on NSObject class, so it becomes NSArray *array = [jsonDict[#"objects"] ifKindOfClass:NSArray.class].
Implementation
#interface NSObject (OptionalDowncast)
- (id)ifKindOfClass:(__unsafe_unretained Class)clazz;
#end
#implementation NSObject (OptionalDowncast)
- (id)ifKindOfClass:(__unsafe_unretained Class)clazz {
return [self isKindOfClass:clazz] ? self : nil;
}
#end
if let is also possible in Objective-C if type is known, so it cannot be combined with previous thing. Easiest way is: for(NSArray *array = [self getItems]; array != nil; array = nil) { ... }, but if you want to use else branch, it gets a bit more complex. I have made SwiftyObjC pod for that, please take a look
Check generic template is not possible during type cast in Objective-C, thus you can cast to NSArray, but you can't cast to NSArray<PFObject>
I don't see iterations over your array: With all that being said, I think best example is (assuming images is an array already):
for(PFFile *file = [images.firstObject ifKindOfClass:PFFile.class]; file != nil; file = nil) {
imageView.file = file;
[imageView loadInBackground];
}
If you need to also iterate over it:
for(id object in images) {
for(PFFile *file = [object ifKindOfClass:PFFile.class]; file != nil; file = nil) {
//operate on file
}
}
You can use Objective-C++ in place of Objective-C. In this you can use the next define:
#define let const auto
Note: it is not the same exactly (Swift has wrapped values, ...) but it makes the work easier.
And through of this define you can use it of this way:
if (let pfobjects = images) {
if (pfobjects.count > 0 {
let imageView = [[PFImageView alloc] init];
imageView.file = pfobjects[0];
imageView loadInBackground();
}
}
To convert your Objective-C class in Objective-C++ class you only must change the extension of implementation file of .m to .mm

New in Objective C. Simple bug at runtime. Thread 1: breakpoint 1.1

I am learning Objective C and I have tried to override my superclass (NSObject) description method in my BNRItem class. Though it seems like I have done everything right, my NSLog does not seem to use my overridden description method. Instead I see a Thread 1 Breakpoint 1.1 in my definition of the description method and more precisely, where I defined the descriptionString.
Here is my console output.
2015-08-30 20:49:00.622 RandomItems[46034:1002101] Zero
2015-08-30 20:49:00.623 RandomItems[46034:1002101] One
2015-08-30 20:49:00.623 RandomItems[46034:1002101] Two
2015-08-30 20:49:00.623 RandomItems[46034:1002101] Three
(lldb)
My main.m file:
#import <Foundation/Foundation.h>
#import "BNRItem.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
// Create a mutable array object, store its address in items variable...
NSMutableArray *items = [[NSMutableArray alloc] init];
//Send the message addObject: to the NSMutableArray pointed
//by the variable item, passing a string each time
[items addObject:#"One"];
[items addObject: #"Two"];
[items addObject: #"Three"];
// Send another message, insertObject:atIndex;, to that same array object
[items insertObject:#"Zero" atIndex:0];
// For every item in the items array ...
for (NSString *item in items){
//Log the description of item
NSLog(#"%#", item);
}
// Create a BNRItem instance and log its instance variables in the console
BNRItem *item = [[BNRItem alloc] init];
// Set item name to Red Sofa
item.itemName = #"Red Sofa";
item.serialNumber= #"A1B2C";
item.valueInDollards = 100;
//
NSLog(#"%#", item);
//Destroy the mutable array object
items = nil ;
}
return 0;
}
My header file:
#import <Foundation/Foundation.h>
#interface BNRItem : NSObject
{
NSString *_itemName;
NSString *_serialNumber;
int _valueInDollards;
NSDate *_dateCreated;
}
- (void)setItemName:(NSString *)str;
- (NSString *)itemName;
- (void)setSerialNumber:(NSString *)str;
- (NSString *)serialNumber;
- (void)setValueInDollards:(int)v;
- (int)valueInDollards;
- (NSDate *)dateCreated;
#end
And finally, my implementation file:
#import "BNRItem.h"
#implementation BNRItem
- (void)setItemName:(NSString *)str
{
_itemName = str;
}
- (NSString *)itemName
{
return _itemName;
}
- (void)setSerialNumber:(NSString *)str
{
_serialNumber = str;
}
- (NSString *)serialNumber
{
return _serialNumber;
}
- ( void )setValueInDollards:(int)v
{
_valueInDollards = v;
}
- ( int )valueInDollards
{
return _valueInDollards;
}
-( NSDate * )dateCreated
{
return _dateCreated;
}
- ( NSString * )description
{
NSString *descriptionString = [[NSString alloc] initWithFormat:#"%# (%#): Worth %d, recorded on %#", self.itemName, self.serialNumber, self.valueInDollards, self.dateCreated];
return descriptionString;
}
#end
It sounds like you have simply set a breakpoint on a line in your -description method. The debugger is stopping your program at the breakpoint. There's no indication of an actual error.
If you hit the continue button in Xcode, your program would probably proceed just fine.
You can disable the breakpoint, tell Xcode to ignore all breakpoints, or delete the breakpoint if you don't want to break there. The breakpoint will look like a blue arrow in the margins to the left of your code. Right-click or Control-click on it to see options.
To make Xcode ignore breakpoints, toggle the breakpoint button in the debugging toolbar. It also looks like a right-pointing arrow. It will be filled in blue if breakpoints are enabled. It will be an outline if they're disabled.

string not populating with array data, even though arrays are not really empty

I am trying to create a non-Document-based application for Mac OS X that randomizes cards for the game of Dominion.
From many of the ones I have tried, the only thing I cannot seem to do is limit the number of sets picked from a selection made by the user, and things worked pretty well in my program, but I am having issues.
I am trying to get the results to print in a custom view, but every time I look at the print preview, nothing shows, except header text, as specified in an NSMutableString.
This piece of code is what is being used to print and is found in MasterViewController:
- (IBAction)print:(id)sender
{
NSMutableString *content = [[NSMutableString alloc] initWithString:#"Cards\r\n\r\n"];
for (int i = 0; i < [supply.game count]; i++)
{
[content appendFormat:#"Card: %# Set: %# Cost: %d\r\n", [supply.game[i] name], [supply.game[i] collection], [supply.game[i] cost]];
}
[content appendFormat:#"\r\n\r\nRequired\r\n\r\n"];
for (int i = 0; i < [[setup supply] count]; i++)
{
NSDictionary* current = [setup supply][i];
NSString* key = [current allKeys][0]; // get the key of the current dictionary must be 0, as there is only one key
int value = [[current valueForKey:key] integerValue]; // variable to hold key value
if (value > 0) {
[content appendFormat:#"%#: %#", key, #"Yes"];
}
else
{
[content appendFormat:#"%#: %#", key, #"No"];
}
}
printView.content = [NSMutableString stringWithString:content];
[printView print:sender];
}
the data initially gets filled into some tableviews, which displays the correct content, and the supply.game array is the exact array that contains cards used for games.
setup is a property that refers to a view controller that populates a table with kinds of cards that may be required for games (e.g. shelters, colonies, ruins, spoils, and potions) and the supply method is supposed to return the array that view controller creates, which is itself not empty, as that table populates properly.
printView is a property that is assigned to a custom view found in MainMenu.xib and is the real view being used to print from.
the printView class looks like this:
header:
#import <Cocoa/Cocoa.h>
#interface PrintView : NSView
{
NSMutableString* content;
}
#property NSMutableString* content;
- (void)drawStringInRect:(NSRect)rect; // method to draw string to page
- (void)print:(id)sender; // method to print
#end
implementation:
#import "PrintView.h"
#implementation PrintView
#synthesize content;
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (void)print:(id)sender
{
[[NSPrintOperation printOperationWithView:self] runOperation];
}
- (void)drawRect:(NSRect)dirtyRect {
NSGraphicsContext *context = [NSGraphicsContext currentContext];
if ([context isDrawingToScreen])
{
}
else
{
[[NSColor whiteColor] set];
NSRect bounds = [self bounds];
if (content == nil || [content length] == 0)
{
NSRectFill(bounds);
}
else
{
[self drawStringInRect:bounds];
}
}
}
- (void)drawStringInRect:(NSRect)rect
{
NSSize strSize; // variable to hold string size
NSPoint strOrigin; // variable used to position text
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSFont fontWithName:#"Helvetica" size:12] forKey:NSFontAttributeName];
[attributes setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
strSize = [content sizeWithAttributes:attributes];
strOrigin.x = rect.origin.x + (rect.size.width - strSize.width)/2;
strOrigin.y = rect.origin.y + (rect.size.height - strSize.height)/2;
[content drawAtPoint:strOrigin withAttributes:attributes];
}
#end
When I check the array sizes for printing operation, the size of the arrays is reported as zero, thus resulting in my current problem
If you need more code, here is code from Github, but I do not have the experimental branch up there, which is where the above code came from, though it should not be too different.
The MasterViewController will show how the supply.game array is made and SetupViewController houses the code that is used to determine what is needed in the game, as well as show how the supply array from [setup supply] is being produced.
MasterViewController has also been added as an object to MainMenu.xib, so I do not know if that affects anything.
Any idea of what I need to do?
Edit: Added in info that might be relevant

Values changing automatically

Hi together I have a Problem:
I read out the actual Values of the Playing media song, and add it to a dictionary.
And then into an Array. If I add a new entry pressing the Button again, all Values of all entrys changing to the same.
Do you have an Idea why?
Here my Code:
- (IBAction)ActionButtonLU:(id)sender
{
MPMediaItem *currentItem = [musicPlayer nowPlayingItem];
NSString *titleString = [currentItem valueForProperty:MPMediaItemPropertyTitle];
NSString *artistString = [currentItem valueForProperty:MPMediaItemPropertyArtist];
NSString *albumString = [currentItem valueForProperty:MPMediaItemPropertyAlbumTitle];
if (titleString == nil) {
titleString = #"";
}
if (artistString == nil) {
artistString = #"";
}
` `if (albumString == nil) {
albumString = #"";
}
[_dictCat1 setObject:titleString forKey:#"Titel"];
[_dictCat1 setObject:artistString forKey:#"Artist"];
[_dictCat1 setObject:albumString forKey:#"Album"];
[_countCat1 addObject:_dictCat1];
[musicPlayer skipToNextItem];
}
You are modifying the same dictionary, _dictCat1, in every call. You need to create a dictionary locally and add that to _countCat1.
[_countCat1 addObject:#{ #"Title": titleString,
#"Artist": artistString,
#"Album": albumString }];
When you add an object to a collection (NSArray, NSDictionary, NSSet etc, including mutable counterparts), the collection doesn't copy it. With [_countCat1 addObject:_dictCat1]; you keep adding the same object to _countCat1 over and over. You need to create new NSDictionary and add that to _countCat1 collection.