Cant access NSImage object or not able "import NSImage.h" - ios

Well I am confused because should be a no brainer.
In Xcode 5 I start a new iphone project.
In ViewDidLoad I begin typing:
NSImage *image ...
Actually at the point of "NSI" ... the NSImage is not available.
I see many other options like NSInteger etc...
So from the start I cant create a NSImage object.
Ok so I look at documentation for NSImage and it clearly says object is declared in both following packages (why are there 2 declarations and which one should I use)
Declared in NSGraphics.h
NSImage.h
but I am not allowed to import any of these packages.I just get red line next to it when I try to do that.
So if I am not allowed to import this package ... why does the documentation give me information about the package that it is in. I am sure I should be able to use it ??
So what daft thing am I doing ?

NSImage.h is an OS X class. You should be using UIImage, NSImage's iOS equivalent. This can get confusing considering a lot of the "NS" prefixed names are shared between iOS and OS X, but an easy way to determine what is available is to have a look at the iOS class references for Foundation.framework or UIKit.framework.
You can also expand the headers group in the frameworks group in Xcode's file inspector to see what headers are available to you.

Related

How to call NSPasteboard withUniqueName from Python using PyObjC

I am attempting to create a new pasteboard using the NSPasteboard class-level function withUniqueName from Python via PyObjC, however I get the error "AttributeError: No attribute withUniqueName".
This is my first use of PyObjC. I did read the PyObjC intro but I could very easily be calling it wrong.
This code yields the error:
from AppKit import *
pb = NSPasteboard.withUniqueName()
Based on the discussion of selectors in the intro, I also tried:
from AppKit import *
pb = NSPasteboard.withUniqueName_()
but that also gave an AttributeError.
This code (excerpted from http://www.macdrifter.com/2011/12/python-and-the-mac-clipboard.html works:
from AppKit import *
pb = NSPasteboard.generalPasteboard()
From the NSPasteboard docs I see that withUniqueName is a class function whereas general is a class variable, so my attempt to invoke withUniqueName in the same way may be errant.
In attempting to determine whether I was just calling withUniqueName wrong or whether PyObjC didn't implement it, I did dir(NSPasteboard). withUniqueName was not in the list, but neither was "general" nor "generalPasteboard". Even grepping through the installed modules, I could not find "general" nor "generalPasteboard", and I know the latter works, so that was frustrating my attempt at discovery. Also I don't understand why the Python code needs to call the variable as generalPasteboard when the name in the Apple docs is just general.
I'm using PyObjC 5.2 installed from PyPI with Python 3.7.0 on Sierra 10.12.6.
Does PyObjC 5.2 support NSPasteboard withUniqueName? If so, what is the correct way to call it? If not, how would I inspect the module/class to know that?
The name withUniqueName is the Swift name of this method, the Objective-C selector is +[NSPasteboard pasteboardWithUniqueName]. This means it can be called like this:
pboard = NSPasteboard.pasteboardWithUniqueName()

Xcode sees only some of similar extensions of a nested class written in separate files

I'm trying to keep my code as readable as it possible by keeping methods and files as short as I can and using nested classes for namespacing. It works fine except some really strange moment.
I have some class used for namespacing.
class Space { }
All classes used within that one are implemented in their own files as extensions.
extension Space {
class SomeClass {
// implementation
}
}
One of those SomeClasses have a number of quite sophisticated initialisers, so I have split them up to their own files as well and implemented it as follows:
extension Space.SomeClass {
convenience init(fromSomeSource source: SourceClass) {
self.init()
// other implementation
}
}
The problem is that some of those files works just fine, but some of them throwing 'SomeClass' is not a member type of 'Space' and I don't know why.
All of them are pretty similar. The only difference is implementation of an initialiser itself. All files are held in the same place and I have no idea why some of them works fine and some not.
I tried to move code from not working files into files that works fine and that works – Xcode agrees to see the code and said nothing against it. But when the very same code lies in its own file – Xcode or compiler doesn't want to understand that SomeClass is really a member of Space.
I tried to clean the build, including manual dumping of ~/Library/Developer/Xcode/DerivedData folder. Nothing helps.
Surely I can put it all in a single file and it will work fine, but what the reason why it so picky in my case?
I've tried to create a new file and move there all contents from one of the bad ones. It works, but only with certain file names. Some names gives the same error again, but it seems that if name is totally new and not similar to any of the existing ones - it works. Magic?
I've encountered similar issue, it seems like the complier is trying to process the file where you extend the nested class before the one where it's defined. Therefore you have this error saying that that Space has no member SomeClass.
The solution I've found is to go to your target settings, open Build Phases.
There, in Compile Sources section you should put the file where you define the nested class above files where you extend it.
This solution seems to even play well with your observation that when you recreate the file it sometimes compiles, because when you recreate the file its position in Compile Sources changes.

How to get the "Created by <name> on <date>" text

So the question is actually simple, but I have no idea how to approach this issue. I know this code is generated by template based on this question:
XCode automatically generated comments?
I want to use the <name> that xcode provides on each mac machine which is unique for it's user, for some types of logs.
EDIT:
This is how the swift template file looks before it's used by Xcode to create my work file:
//
// ___FILENAME___
// ___PROJECTNAME___
//
// Created by ___FULLUSERNAME___ on ___DATE___.
//___COPYRIGHT___
//
Surely, there is no point in parsing it.
The question is: Does anyone knows how I can get this name using swift in my application?
I searched for an answer here/Google but so far no luck.
I don't know how to read the header. But you can do it otherwise.
First if you need the creation-date of a file, you can use the NSFileManager:
var path = "path/to/your/file/"
var fileAttribs:NSDictionary = NSFileManager.defaultManager().attributesOfFileSystemForPath(path, error: nil)!
var creationDate = fileAttribs.objectForKey(NSFileCreationDate)
Also if you need the full username, you can use the function NSFullUserName() or NSUserName(). It should return the same string as __FULLUSERNAME__
var fullUsername = NSFullUserName()
var username = NSUserName()
Sometimes in the iOS Simulator, this username is empty, but in a real app, it should work properly.
That text written at template instantiation time — that is, when you create a new Xcode project (or a new file in an existing project using the File > New > File... templates). You can't read the contents of the source file your code was compiled from. (Well, unless you ship that file along with your compiled binary, and read it in like any other text file.)
But that's just text substitution — it can be done anywhere in the file, not just in the comment headers. So you could create your own file or project templates, and in the template files, put those substitution macros in code instead of in comments:
let schmoeWhoCreatedThisFile = "___FULLUSERNAME___"
Here's a tutorial found in a couple seconds of web searching that has the full details on creating templates and the substitution macros you can use in them.
Remember, substitution happens when you create a new file or project — if you're looking for who made the latest change to your source file or who built the app that shipped to your customers, you're barking up the wrong tree. Some of those sorts of things you can do with source control; others are more a matter of (human-defined, human-executed) policy for you or or your organization.

What is the best way to avoid duplicate symbols in project that will use my iOS framework and one of the dependencies?

Here is a quotation from the other post:
I'm working in a iOS project that includes a static library created by another company. The library include an old version of AFNeworking and I don't have any source files.
Now i need to use a more recent (and less bugged) version of afneworking, but i cannot include the same class twice in the project (of course) because all the "duplicate symbols"
My problem is that I'm preparing an iOS framework and I want to avoid this kind of situation in the future. I'm not talking about AFNetworking, but other quite popular iOS framework. In addition I applied some custom changes in the original framework code.
The one way to avoid "duplicate symbols" and "Class X is implemented in both Y and Z. One of the two will be used" that comes to my mind is to add some prefix to the original framework classes, but is this the right solution?
UPDATE 1:
I tried to apply John's solution but no joy. I have created a simplified project (here is the link to the repo) with two classes FrameworkClass which is present in framework target only, and SharedClass which is present in both framework and application targets, so maybe you can see if I'm doing something wrong. After application did launch I'm still getting:
objc[96426]: Class SharedClass is implemented in both .../TestFramework.framework/TestFramework and .../SymbolsVisibilityTest.app/SymbolsVisibilityTest. One of the two will be used. Which one is undefined
UPDATE 2:
Here is my output from nm based on the provided sample project's framework-output:
0000000000007e14 t -[FrameworkClass doFramework]
0000000000007e68 t -[SharedClass doShared]
U _NSLog
U _NSStringFromSelector
00000000000081f0 s _OBJC_CLASS_$_FrameworkClass
U _OBJC_CLASS_$_NSObject
0000000000008240 s _OBJC_CLASS_$_SharedClass
00000000000081c8 s _OBJC_METACLASS_$_FrameworkClass
U _OBJC_METACLASS_$_NSObject
0000000000008218 s _OBJC_METACLASS_$_SharedClass
0000000000007fb0 s _TestFrameworkVersionNumber
0000000000007f70 s _TestFrameworkVersionString
U ___CFConstantStringClassReference
U __objc_empty_cache
U _objc_release
U _objc_retainAutoreleasedReturnValue
U dyld_stub_binder`
UPDATE 3:
I did manage to "hide" SharedClass symbols by applying the solution by #bleater and my output from nm is now:
U _NSLog
U _NSStringFromSelector
00001114 S _OBJC_CLASS_$_FrameworkClass
U _OBJC_CLASS_$_NSObject
00001100 S _OBJC_METACLASS_$_FrameworkClass
U _OBJC_METACLASS_$_NSObject
U ___CFConstantStringClassReference
U __objc_empty_cache
U _objc_release
U _objc_retainAutoreleasedReturnValue
U dyld_stub_binder`
But I'm still getting double implementation warning in Xcode.
You should limit the visibility of symbols in any framework or library you are developing. Set the default visibility to hidden, and then explicitly mark all the functions in the public interface as visible.
This avoids all the problems you have described. You can then include any version of any public library (AFNetworking, SQLite, etc.), without fear of future conflict because anything linking to your framework or library won't be able to "see" those symbols.
To set the default visibility to hidden you can go into the project settings and set "Symbols Hidden by Default" to YES. It is set to NO unless you change it.
There are at least a couple of ways to mark the symbols from your public interface as "Visible". One is by using an exports file, another is to go through and explicitly mark certain functions as visible:
#define EXPORT __attribute__((visibility("default")))
EXPORT int MyFunction1();
The define is obviously just for convenience. You define EXPORT once and then just add EXPORT to all of your public symbols.
You can find official apple documentation on this here:
Runtime Environment Programming Guide
Update:
I took a look at your sample project, and it looks like I pointed you in the wrong direction. It appears that you can only truly hide C and C++ symbols. So if your were having this problem with a C lib (like sqlite), setting the default visibility to hidden would work. It looks like the nature of the Objective C runtime prevents you from truly making the symbols invisible. You CAN mark the visibility on these symbols, but with Objective-C it appears that is just a way to have the linker enforce what you should or shouldn't be able to use from the library (while still leaving them visible).
So if you redefine a Objective-C symbol in different compilation unit with the same name (by perhaps compiling in a new version of a popular open source library), then you will still have a conflict.
I think your only solution at this point is to do what you first suggested and prefix the symbols you are including into your framework with a unique identifier. It isn't a very elegant solution, but with the limits of the objective C runtime I believe it is probably the best solution available.
So the blog post by Kamil Burczyk was a good starting point, thanks for the hint Michał Ciuba! It has covered most of the symbols, but it didn't cope with categories and class clusters. You can see what category methods are still exposed without any change by invoking nm with parameter list sth like:
nm MyLibrary | grep \( | grep -v "\[LIBRARYPREFIX" | grep -v \(MyLibrary | grep -v ") prefix_"
When it comes to categories we have 3 groups of categories, and they all require a specific, different approach:
Categories on classes that has been renamed by NamespacedDependencies.h
Categories on classes not renamed by NamespacedDependencies.h
Categories on class clusters like NSString, NSArray...
Ad 1.
Everything is ok - class name will be prefixed so category will exist on prefixed sumbol in object file
Ad 2.
This problem occours whenever inside of the dependency we have category on a class like NSObject. It would be exposed without any change in object file, thus would cause a conflict. My approach was to internally rename NSObject to PREFIX_NSObject, this ofcourse requires me also to create and add the PREFIX_NSObject class implementation to the project (empty implementation, just a subclass of original NSObject)
#import "PREFIX_NSObject.h"
#ifndef NSValueTransformer
#define NSValueTransformer __NS_SYMBOL(NSObject)
#endif
Ad 3.
We cannot apply Ad 2. approach here. Actual objects created by let's say PREFIX_NSArray class methods are still of type that wont derive from my presumable PREFIX_NSArray class, so this doesn't make sense as category methods defined on PREFIX_NSArray won't be visible on NSArray derived objects. I ended up by manually prefixing methods of those categories in source code.
It's kind of crazy workflow, but at least gives warranty that everything will be 'invisible' and won't cause a conflict.
It's always good idea to run nm to check if all category symbols are hidden:
nm MyLibrary | grep \( | grep -v "\[LIBRARYPREFIX" | grep -v \(MyLibrary | grep -v ") prefix_"

Expected identifier for every occurance of "(Class)class" in LARSAdController

I'm currently trying to add LARSAdController to my iOS project with no success.
As soon as i import the files via #import "LARSAdController.h" in my AppDelegate.h the build process fails and on every occurance of (Class)class in LARSAdController.h i get the cryptic error "Expected identifier". BTW I'm using cocoapods.
Example:
- (void)registerAdClass:(Class)class;
which seems fine to me...
If i create a blank project and import the files they compile, so the problem must be in some relation to my code. Anyone got an idea what may cause this?
Thanks for any help in advance!
class is a reserved word in C++, so I would imagine that some of your project uses Objective-C++.
To solve this, use #import LARSAdController.h in Objective-C implementation files only, and remove its use from header files. You can use #class to forward-declare any occurrences of whatever classes are defined in LARSAdController.h in header files (this is best-practise anyway).
If you need to use LARSAdController from an Objective-C++ class then this is more complicated and you will need to use an Objective-C proxy object or modify their header files (which isn't ideal).

Resources