I have an issue that I've figured out how to fix but I want to understand why it doesn't work -- because it makes no sense to me. Here's a minimal example that demonstrates my issue:
import XCTest
import CoreLocation
class ExampleTests: XCTestCase {
var okay: ext!
// this test works fine
func testOkay(){
okay = ext()
XCTAssertNotNil(okay)
}
// this test crashes with EXC_BAD_ACCESS(code=1, address=0x10)
func testNotOkay(){
let notOkay: ext
notOkay = ext()
XCTAssertNotNil(notOkay)
}
}
extension ExampleTests {
class ext : CLPlacemark{
}
}
I'm following a book to develop a simple TodoList application that uses CoreLocation to geocode addresses. As part of testing, I had to create a mock CLPlacemark object to test the geocoding functionality.
In the book, I was told I had to declare a variable for this mock as a property of the Test class because otherwise "the test would crash since the place mark is accessed outside of its definition scope."
This can be seen in the example above. testOkay() works fine because okay was declared as a class property. testNotOkay() crashes with an EXC_BAD_ACCESS error, because I've tried to instantiate a new instance of ext within the function.
Now, if I do not extend CLPlacemark, the problem goes away -- i.e. I can declare variables of type ext in a function or as a property of the class with no issues.
What is going on here? I see no reason why the second example should crash while the first one works. In my actual code, it seems frivolous to declare my mock placemark instances as class properties when they're only used in one or two functions. There must be something I don't understand about Swift that is causing this problem.
Thanks!!
I recently run into this issue when testing feature which required providing predefined CLPlacemark instances as an input. After some research I found that someone had similar problem with CLBeacon class.
EXC_BAD_ACCESS when setting a CLBeacon to nil
Placemark objects are typically generated by a CLGeocoder object, although you can also create them explicitly yourself.
Despite Apple documentation saying that you can create CLPlacemark instances by yourself. This class is not a nice guy when it comes to subclassing. It depends on a private class called CLPlacemarkInternal which is nil when you create an instance. On the image below you can see how this object looks in debugger. The _internal ivar has value of 0x0 which is nil.
Crash with EXC_BAD_ACCESS message occurs when the object you instantiated gets deallocated. Regardless whether you go out of scope or assign another object (or nil) to the variable. Why is it happening? This is a question to Apple developers. But below you can find some workarounds other people implemented.
http://szulctomasz.com/2015/07/01/ios-unit-testing-in-swift-and-clplacemark-mocking.html
Extending CLPlacemark results in EXC BAD ACCESS
I have also experienced the exact same issue.
I resorted to subclassing MKPlacemark instead.
This finally allowed me to set the desired mock properties I needed to get my test to past
Related
I'm getting a bizarre error message from the Swift compiler:
<unknown>:0: error: 'required' initializer 'init(arrayLiteral:)' must be provided by subclass of 'NSSet'
Foundation.NSSet:2:33: note: 'required' initializer is declared in superclass here
required public convenience init(arrayLiteral elements: Any...)
^
Note that none of my code is subclassing NSSet (nor Set). So I have no idea why Swift thinks I was doing it at all, not to mention wrongly.
My project is a little special in that I have Objective-C classes that are calling C++ code (through Objective-C) and a module.map file to let Swift call into a C library.
The error occurs when compiling Swift files (I get it from several Swift files, but only some of them use the C library, but all of them so far seem to be talking to ObjC classes). As you can see, Swift has no line number for its error where someone is subclassing NSSet though.
Has anyone seen this? Does anyone know how to diagnose this issue? I tried commenting out bits of the code, but I can't seem to find anything that helps track this issue down.
To emphasize: I am not doing any subclassing of NSSet. I'm not even using NSSet in my code, I think. That is something the Swift compiler just seems to be making up.
Update: Another question gave me the idea that it may be related to instantiating an instance from a Class object. I have a class that has a Class that I later want to instantiate:
#interface MYInfo : NSObject
#property Class myClass;
#end
Later I use that from Swift to instantiate it:
guard let myClass = info.myClass.init() as? MyClass else { return }
If I remove this last line, the error message disappears.
So figured it out, thanks to that other question (which is quite different though):
Swift Compiler is REALLY stupid when you try to init a variable typed as ObjC's Class type and presents the misleading error 'required' initializer 'init(arrayLiteral:)' must be provided by subclass of 'NSSet' even though NSSet is not involved. I guess NSSet is the first or last ObjC init method it knows or something.
Swift compiler also shows this error on random source files (even empty ones!) because of the "magic" way in which Swift parses all other files in the project so you can reference classes in them without an include statement like C has it.
The correct way to instantiate a Class is to first typecast it:
guard let myClass = info.myClass as? (NSObject & MyClass).Type else { return }
let myInstance = myClass.init()
This was way harder to figure out than it should have been.
This is a code block in Alamofire/Manager.swift:
It is inside a class named "public class Manager"
public static let sharedInstance: Manager = {
let configuration: NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPAdditionalHeaders = Manager.defaultHTTPHeaders
return Manager(configuration: configuration)
}()
Obviously, this is "let something equals the closure," but what I don't get is what does the "()" in the end of the line mean?
To defer the execution of the code? How? (It seems to me that the execution won't be deferred as it has the "()"? And I am wondering why this is not causing the existing of a memory circle? It returns the Manger itself and the returned new instance will also do the same, returning a new self...
Why not a key word "lazy"?
I have a strange feeling that i've seem this usage somewhere else too. I'm learning Swift for 60 days now. Am I fast or slow? How to be a iOS developer also?(I mean how to be a real one, not enroll the program)
For now I'm kind of confused and reading all the source code I could get. Sometimes I feel the official docs and Xcode sucks and I don't know how to read a source code scratch. Any tips and advice?
This initializes sharedInstance with the result of the closure (without the parens at the end it would just initialize it to the closure itself) It's a standard syntax for initializing variable with an initializer too complex for a simple expression. In this multiple statements are required so that the HTTPAdditionalHeaders can be initialized.
Okay, I've made a mistake. The trick lies that the sharedInstance used a key word "static" This is common, but in python, which I am most familiar with, do not use this key word.
According to the official guide:
“You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.”
Apple Inc. “The Swift Programming Language”. iBooks. https://itun.es/cn/jEUH0.l
the answer is at the session name "Setting a Default Property Value with a Closure or Function": https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID231
I have this case where I just Call the init of Class I made this class is subclass of NSObject.
- (instancetype)initArray
{
self = [super init];
if (self) {
//Do Some Logic
}
return self;
}
This is my Call from the App Delegate
CategoryLoader *categoryLoader = [[CategoryLoader alloc]initArray];
Whats driving me crazy is that:
Although it returns nil it goes into the if condition
It doesn't return nil on other computer with other Xcode
Please note that both Xcode's are 6.3
Solutions i tried:
Cleaned Cache of Xcode
Deleted the class and created a new one
Reinstalled Xcode
Here is a Screenshot of whats happening:
Any suggestions why could it be returning nil from NSObject and what can i do next ?
Thank you
NSObject’s implementation of init should never return nil. This is documented in the NSObject Class Reference: although slightly confusing, the key part is
The init method defined in the NSObject class does no initialization; it simply returns self.
If you are observing it retuning nil, either something is not setup how you expect (perhaps the class isn’t a direct subclass of NSObject), or you are somehow interpreting the results incorrectly, or there is something wrong at another level. The fact that you observe different results on different machines suggests it might be at another level, like Xcode, the operating system, or the hardware. I can’t help much there; try rebooting.
Also, your method ought to be named init not initArray. This is not a requirement but a very strong convention. You can read about Object Initialization in Apple’s Concepts in Objective-C Programming
Ok. That was the problem:
The the scheme was on Release Mode. In this case the watch window displays nil in most of the objects. When I printed the value of self on NSLog it printed its value. The only difference between me and the other Xcode was the scheme.
So the solution is to edit the scheme of the project to be debug.
Thank you for your support
This might be a silly question. I'm learning objective C (iOS) by studying the code and I came across the expression
[InstanceName class];
What does it do?
I tried to search for class method but It just pops up difference between class method and instance method etc. I guess it might give some sort of class object but I have no idea what is the purpose of the statement.
the original code is Sample Facebook App (scrumptious) using FB SDK....
If you see something like this as a standalone expression....
[InstanceName class];
... then the code is most likely forcing the execution of the +initialize method on said class. The first time any method is invoked on a class, the +initialize method will be invoked prior by the runtime. So, have a look at InstanceName and see if it has a +initialize method.
Note that forcing +initialize to execute in this fashion is a sure sign of bad design. +initialize should never need to be forced like this and should not have execution order dependencies.
There is a legitimate additional reason why this line of code might exist. By referring to InstanceName with a hard reference, it'll force the linker to link in all symbols in the library. (If you don't have a hard reference to at least one symbol in a library -- a .a -- some linkers will simply drop the library from the link unit entirely.)
It gets the class of the object.
So for instance if InstanceName is an instance of class Foo
[InstanceName class]; will return Foo, in a variable of type Class
You can use class_getClassName to get an NSString from this class to log it.
class is a method inherited from NSObject. It lets you get the instance of the class object representing the class of the instance on which the method is called.
It can be used to examine the metadata of the current object. For example, you can use class method to determine if a given object is of a particular class:
if ([sender isKindOfClass:[UIButton class]]) {
...
}
It returns the class of the object. Suppose you have an array of UIView subclasses you created and you want to perform some action only to those who belong to a certain class. You could loop through the array and check for each object's class:
for (id view in myViews) {
if ([view isKindOfClass:[MyUIViewSubclass class]]) {
// Do something
}
}
I'm writing a static library for iOS. I want to programmatically figure out if CoreLocation is added to the project, is there any way to do that?
Probably something like:
if(NSClassFromString(#"CLLocationManager"))
{
NSLog(#"CoreLocation is available");
}
Would do it. NSClassFromString takes an NSString and checks whether there's a class of that name currently available in the runtime. If so then it returns the Class object, otherwise it returns nil. The if statement there effectively compares to nil.
So, the logic you're applying is "does a class called CLLocationManager currently exist?", which is a proxy for checking that CoreLocation is loaded because it's one of the fundamental classes to that framework.